mirror of
https://framagit.org/hubzilla/core.git
synced 2026-06-21 09:01:15 -04:00
Compare commits
121 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bbcf7e9aa1 | ||
|
|
45a2ebc662 | ||
|
|
aece22aee6 | ||
|
|
9904eba277 | ||
|
|
7c0f98a513 | ||
|
|
8d25b6eae4 | ||
|
|
9369085835 | ||
|
|
9c20b4809a | ||
|
|
00b3039b6e | ||
|
|
2695094d16 | ||
|
|
bcfdb73001 | ||
|
|
1650809cd8 | ||
|
|
991815469f | ||
|
|
c5fb8eafac | ||
|
|
a0c98e070e | ||
|
|
7d6202be13 | ||
|
|
4ba470318c | ||
|
|
e948aaf751 | ||
|
|
3789017ca0 | ||
|
|
48f5acced3 | ||
|
|
13e2d2f654 | ||
|
|
8d45fd36a1 | ||
|
|
6ed2301a94 | ||
|
|
a0eb701503 | ||
|
|
39f9a38b23 | ||
|
|
590c0ea778 | ||
|
|
f36d8e4bd2 | ||
|
|
4e3bec8a35 | ||
|
|
eec918bf4a | ||
|
|
13002af4c3 | ||
|
|
40c63a7f12 | ||
|
|
3d0621eb8c | ||
|
|
030c02dfdc | ||
|
|
00c1509549 | ||
|
|
8122c40252 | ||
|
|
787c63b7ae | ||
|
|
ee988edc83 | ||
|
|
a71f5e123a | ||
|
|
7579749adc | ||
|
|
cf408c3fac | ||
|
|
0c97792ca7 | ||
|
|
84d63b3b67 | ||
|
|
63aa50eb8d | ||
|
|
7fb13f23fe | ||
|
|
65156a0e4d | ||
|
|
e3eebcd95d | ||
|
|
9eff1a08d4 | ||
|
|
cfcac590c3 | ||
|
|
872415bffe | ||
|
|
a46b781664 | ||
|
|
b77fac43c8 | ||
|
|
2b4b409c01 | ||
|
|
67aa547c48 | ||
|
|
e288f33776 | ||
|
|
a5aab4c30e | ||
|
|
cf7613b3e0 | ||
|
|
fa01a2b348 | ||
|
|
65c8de3410 | ||
|
|
d9b262348f | ||
|
|
ea9d2a0acf | ||
|
|
5d55006be8 | ||
|
|
d9ced0c6bf | ||
|
|
8d4d1b17c7 | ||
|
|
453f6a08a3 | ||
|
|
b6560e5456 | ||
|
|
b805f48c32 | ||
|
|
33b78a4943 | ||
|
|
48b187ccd8 | ||
|
|
f680bba3e6 | ||
|
|
09aabc6b41 | ||
|
|
0dd456c653 | ||
|
|
97ba14cbe0 | ||
|
|
ee6367a549 | ||
|
|
fc52d1b44f | ||
|
|
bfce562a46 | ||
|
|
8d8a7f44e1 | ||
|
|
6c8da6ce36 | ||
|
|
e19a050b92 | ||
|
|
a13bf6a3fe | ||
|
|
0edf761499 | ||
|
|
bf76d5981f | ||
|
|
33fcb43173 | ||
|
|
ffae47f523 | ||
|
|
c07cdb30fa | ||
|
|
546c4fcad2 | ||
|
|
0a17b83578 | ||
|
|
2782b6d724 | ||
|
|
dc076a4c00 | ||
|
|
a550c7c853 | ||
|
|
7a3d59bff3 | ||
|
|
82a3b71a51 | ||
|
|
e39b2eb7b9 | ||
|
|
9f8248cc9c | ||
|
|
71e4326606 | ||
|
|
7eb6f9b11d | ||
|
|
4625ffa6b4 | ||
|
|
3e6a646603 | ||
|
|
324b281813 | ||
|
|
03d1f3383e | ||
|
|
69a23c604d | ||
|
|
174469970a | ||
|
|
89b254dc1c | ||
|
|
8e51988e96 | ||
|
|
52e279f443 | ||
|
|
4efa853690 | ||
|
|
2d2c9fa519 | ||
|
|
27efb887d2 | ||
|
|
ccd52584a4 | ||
|
|
ab0fdb13d4 | ||
|
|
2bca44ed25 | ||
|
|
eab08d0bcb | ||
|
|
d3f00704bd | ||
|
|
1e1a7109a9 | ||
|
|
0165f44063 | ||
|
|
8fc0e41beb | ||
|
|
3ad63a6e82 | ||
|
|
392cb020aa | ||
|
|
884b612ffc | ||
|
|
ae0d138d2a | ||
|
|
48ef4744ac | ||
|
|
a17cb75baf |
@@ -27,9 +27,7 @@ if you look for more choices. The main differences are:
|
||||
- graphical installer whiptail
|
||||
- The script stops (fails) if it finds results of a previous installation. (The [debian-setup.sh](https://framagit.org/ojrandom/core/-/tree/dev/.debianinstall) will just jump over it.)
|
||||
- If something fails the script tries to clean up everything that was installed up to the point of failure. (That might cause trouble if certbot registered a certificate already.)
|
||||
- The script under [homeinstall](https://framagit.org/hubzilla/core/-/tree/master/.homeinstall) seems to be an older version of the scripts used for Streams
|
||||
+ [autoinstall](https://codeberg.org/streams/streams/src/branch/dev/contrib/autoinstall)
|
||||
+ [easyinstall](https://codeberg.org/streams/streams/src/branch/dev/contrib/easyinstall)
|
||||
- The script under [homeinstall](https://framagit.org/hubzilla/core/-/tree/master/.homeinstall) seems to be an older version of the scripts used for Streams, i.e. [autoinstall](https://codeberg.org/streams/streams/src/branch/dev/contrib/autoinstall) and [easyinstall](https://codeberg.org/streams/streams/src/branch/dev/contrib/easyinstall)
|
||||
|
||||
## Preconditions
|
||||
|
||||
@@ -153,6 +151,3 @@ to boot the Rapsi to the client console.
|
||||
|
||||
DO NOT FORGET TO CHANGE THE DEFAULT PASSWORD FOR USER PI!
|
||||
|
||||
## Reminder for Different Web Wervers
|
||||
|
||||
For those of you who feel adventurous enough to use a different web server (i.e. Lighttpd...), don't forget that this script will install Apache or Nginx and that you can only have one web server listening to ports 80 & 443. Also, don't forget to tweak your daily shell script in /var/www/ accordingly.
|
||||
|
||||
@@ -93,9 +93,8 @@ freedns_key=
|
||||
# If left empty, both your database and user will be named after your zot instance (hubzilla, zap or misty)
|
||||
# Use custom name, at least fo the database, if you plan to run more than one hub/instance on the same server
|
||||
#
|
||||
zotserver_db_name=
|
||||
zotserver_db_user=
|
||||
zotserver_db_pass=$db_pass
|
||||
db_name=hubzilla
|
||||
db_user=hubzilla
|
||||
#
|
||||
#
|
||||
# Password for package mysql-server
|
||||
|
||||
@@ -150,7 +150,7 @@ function install_sendmail {
|
||||
function install_php {
|
||||
# openssl and mbstring are included in libapache2-mod-php
|
||||
print_info "installing php..."
|
||||
nocheck_install "libapache2-mod-php php php-pear php-curl php-gd php-mbstring php-xml php-zip"
|
||||
nocheck_install "libapache2-mod-php php php-pear php-curl php-gd php-mbstring php-xml php-zip php-intl php-bcmath"
|
||||
phpversion=$(php -v|grep --only-matching --perl-regexp "(PHP )\d+\.\\d+\.\\d+"|cut -c 5-7)
|
||||
sed -i "s/^upload_max_filesize =.*/upload_max_filesize = 100M/g" /etc/php/$phpversion/apache2/php.ini
|
||||
sed -i "s/^post_max_size =.*/post_max_size = 100M/g" /etc/php/$phpversion/apache2/php.ini
|
||||
@@ -256,12 +256,18 @@ function create_zotserver_db {
|
||||
then
|
||||
Q1="CREATE DATABASE IF NOT EXISTS $db_name;"
|
||||
Q2="GRANT USAGE ON *.* TO $db_user@localhost IDENTIFIED BY '$db_pass';"
|
||||
Q3="GRANT ALL PRIVILEGES ON $name.* to $db_user@localhost identified by '$db_pass';"
|
||||
Q3="GRANT ALL PRIVILEGES ON $db_name.* to $db_user@localhost identified by '$db_pass';"
|
||||
Q4="FLUSH PRIVILEGES;"
|
||||
SQL="${Q1}${Q2}${Q3}${Q4}"
|
||||
mysql -uroot -p$mysqlpass -e "$SQL"
|
||||
else
|
||||
echo "database $db_name does exist already"
|
||||
Q1="CREATE DATABASE IF NOT EXISTS $db_name;"
|
||||
Q2="GRANT USAGE ON *.* TO $db_user@localhost IDENTIFIED BY '$db_pass';"
|
||||
Q3="GRANT ALL PRIVILEGES ON $db_name.* to $db_user@localhost identified by '$db_pass';"
|
||||
Q4="FLUSH PRIVILEGES;"
|
||||
SQL="${Q1}${Q2}${Q3}${Q4}"
|
||||
mysql -uroot -p$mysqlpass -e "$SQL"
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
16
.gitignore
vendored
16
.gitignore
vendored
@@ -48,9 +48,10 @@ doc/html/
|
||||
.zotshrc
|
||||
# external repositories for themes/addons
|
||||
extend/
|
||||
# files generated by phpunit
|
||||
|
||||
# exclude test results and cache
|
||||
tests/.cache
|
||||
tests/.phpunit.result.cache
|
||||
tests/.phpunit*
|
||||
tests/results/
|
||||
|
||||
## exclude IDE files
|
||||
@@ -67,7 +68,6 @@ nbproject/
|
||||
# PHPStorm
|
||||
.idea/
|
||||
|
||||
|
||||
## composer
|
||||
# locally installed composer binary
|
||||
composer.phar
|
||||
@@ -87,6 +87,7 @@ vendor/bin/php-parse
|
||||
vendor/bin/phpcbf
|
||||
vendor/bin/phpcs
|
||||
vendor/bin/phpmd
|
||||
vendor/bin/phpstan*
|
||||
vendor/bin/phpunit
|
||||
vendor/composer/pcre/
|
||||
vendor/composer/xdebug-handler/
|
||||
@@ -98,18 +99,11 @@ vendor/pdepend/
|
||||
vendor/phar-io/
|
||||
vendor/php-mock/
|
||||
vendor/phpmd/
|
||||
vendor/phpstan
|
||||
vendor/phpunit/
|
||||
vendor/psr/container/
|
||||
vendor/sebastian/
|
||||
vendor/squizlabs/
|
||||
vendor/symfony/config/
|
||||
vendor/symfony/dependency-injection/
|
||||
vendor/symfony/deprecation-contracts/
|
||||
vendor/symfony/filesystem/
|
||||
vendor/symfony/polyfill-ctype/
|
||||
vendor/symfony/polyfill-mbstring/
|
||||
vendor/symfony/polyfill-php80/
|
||||
vendor/symfony/service-contracts/
|
||||
vendor/theseer/
|
||||
# /info is a directory containing site-specific HTML documents
|
||||
/info/
|
||||
|
||||
@@ -32,6 +32,7 @@ before_script:
|
||||
- apt-get install -yqq libicu-dev libjpeg-dev libpng-dev libpq-dev libyaml-dev libzip-dev mariadb-client postgresql-client unzip zip
|
||||
- pecl install xdebug yaml
|
||||
- docker-php-ext-enable xdebug yaml
|
||||
- docker-php-ext-configure gd --with-jpeg=/usr/include/
|
||||
- docker-php-ext-install gd bcmath intl pdo_mysql pdo_pgsql zip
|
||||
|
||||
# Install composer
|
||||
|
||||
60
CHANGELOG
60
CHANGELOG
@@ -1,3 +1,63 @@
|
||||
Hubzilla 10.2 (2025-03-17)
|
||||
- Allow to send signed requests from the zot_probe tool
|
||||
- Print an error message if OWA fails
|
||||
- Remove possible leading @ before processing webfinger address
|
||||
- Updated debian install script
|
||||
- Calculate observer.baseurl from xchan_url instead of xchan_connurl
|
||||
- Refactor unparse_url() to allow return of a custom field set only and add tests
|
||||
- Slightly improve event object rendering
|
||||
- Update smarty library to version 5 for PHP 8.4 compatibility
|
||||
- Remove vendor/symfony from gitignore file
|
||||
- Update composer libraries
|
||||
- Add contextHistory field to activities and prefer it over context when consuming
|
||||
- Implement highlight button in jot editor
|
||||
- Add test results and PHPStan to gitignore
|
||||
- Update spanish strings
|
||||
- Remove EpubMeta library in favor of a custom solution
|
||||
- Configue gd for jpeg support in CI
|
||||
- Add error message on missing owa auth headers
|
||||
- Add Zotlabs\Tests namespace to autloader in dev
|
||||
- Add dba_pdo::update method
|
||||
- Add dba_pdo::insert method
|
||||
- Rewrite redbasic javascript to remove jquery dependency
|
||||
- Add security policy SECURITY.md
|
||||
|
||||
Bugfixes
|
||||
- Fix notifications for likes on our comments
|
||||
- Fix fullscreen view
|
||||
- Fix boxy scheme text alignment for comments
|
||||
- Fix poll date string to match with the autotime string
|
||||
- Fix owner hash not set correctly when editing a post/comment
|
||||
- Fix an issue where some participants could not post to forums
|
||||
- Fix navbar selector conflict with possible additional navbars when using a cover photo
|
||||
- Fix target and tgt_type not set for sourced rss items if we rewrite them to our own
|
||||
- Fix auto save draft not set correctly
|
||||
- Fix cover height calculation
|
||||
|
||||
Addons
|
||||
- Diaspora: revisit import_diaspora_account()
|
||||
- Pubcrawl: escape quotation marks in ActivityStreams link header
|
||||
- Wiki: fixed wiki_page_list.tpl to use bootstrap class for layout
|
||||
- BBmath: fix orientation for inline math
|
||||
- BBmath: document imagemagick permissions
|
||||
- Pubcrawl: ensure we select the correct hubloc hash when extending recipients list
|
||||
- Msg_footer: do not add footer on edit, also dismiss anything but a create activity
|
||||
- Pubcrawl: refactor activitypub addressing
|
||||
- Wiki: added space to preview panel
|
||||
- Startpage: update help text and some cleanup
|
||||
|
||||
|
||||
Hubzilla 10.0.8 (2025-02-01)
|
||||
- Fix duplicating terms/iconfig in addToCollectionAndSync()
|
||||
- Refactor Daemon/Importdoc for better SQL performance when looking up outdated entries
|
||||
- Tweak SQL in mod sse_bs for possible performance improvements
|
||||
- Fix PHP warnings
|
||||
- Do not run post_local hook on add activities in pubcrawl addon
|
||||
- Do not run post_local hook on add activities in diaspora addon
|
||||
- Remove old rawmsg/fields before storing new rawmsg in pubcrawl addon
|
||||
- Fix retractions in diaspora addon
|
||||
|
||||
|
||||
Hubzilla 10.0.7 (2025-01-22)
|
||||
- Fix ownership check in consume_feed()
|
||||
- Fix toast() if notification contains non-ascii characters
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
"air" is a branch name for revision of Account-Invite-Register at the Hubzilla project
|
||||
|
||||
Invite:
|
||||
* Rewritten and now language template driven
|
||||
* Selectable templates for the invite mails
|
||||
* Invitor may add personal notes in the mailtext
|
||||
+ Invite codes are bound to the recipients email address
|
||||
* Invite mod never more creates accounts
|
||||
* new db scheme for table register
|
||||
* existing register table will be migrated to the new schema even when detected at runtime
|
||||
* Bugfix: creating invite codes when admin only calls Invite w/o any further action
|
||||
* account library revision also together with invite mod
|
||||
* Depending on config: Users may send invitations also
|
||||
* Invitations expires, controlled by the invitor
|
||||
* Changed and new configs:
|
||||
* * invitation_only As usual before
|
||||
* * invitation_also Beside other registration policies, invitations may be used also
|
||||
* * invitation_max_per_day defaults 50, may be changed in adminUI admin>site
|
||||
* * invitation_max_per_user defaults 4
|
||||
* Requirements:
|
||||
* * Addon language has to be installed
|
||||
|
||||
Register:
|
||||
* Register panel (form) and js interaction changed
|
||||
* Unused registrations expire
|
||||
* Depending on config, anonymous registrations (w/o email) are supported
|
||||
* :... dont't panic, that may let grow security
|
||||
* Even anonymous users have to confirm their registration
|
||||
* Registrations may be enabled / disabled time driven for each day in the week (dudy)
|
||||
* Unsoliced registration floods may be blocked
|
||||
* Limited registrations from one single source ip
|
||||
* Using one additional log file, to easy interfare with f2b
|
||||
|
||||
Account:
|
||||
* An user account always becomes created only if all depending conditions are satisfied
|
||||
* AdminUI for site configuration, accounts and registrations enhancements
|
||||
* Still untouched, but accountUI needs enhanced async control in case for mass delete
|
||||
with deep level of recursion cascade of the dependencies (channels etc). An open TODO
|
||||
since years for instances with many much users and channels.
|
||||
|
||||
History:
|
||||
2020.03 Hubzilla Prod version 4.6 (master branch) of hubzilla/core was the base for AIR
|
||||
that was assigned Version 4.6.2 at sn/core
|
||||
2021.02 Hubzilla Prod version 5.2.1 (master branch) of hubzilla/core was new base for AIR
|
||||
that was assigned version 5.2.2 at sn/core (air.5)
|
||||
plus adjustment of hubzilla 5.2.2 (master) to sn/core (air.5) version 5.2.9
|
||||
|
||||
|
||||
31
SECURITY.md
Normal file
31
SECURITY.md
Normal file
@@ -0,0 +1,31 @@
|
||||
# Hubzilla Security Policy
|
||||
|
||||
The [Hubzilla] Project takes security, privacy and user control over personal data seriously. We ask that any security issues be disclosed to us in a responsible manner to allow us time to remediate the issues, and site administrators time to upgrade before information about the issue is made public.
|
||||
|
||||
This document outlines security procedures and policies for the Hubzilla project. It covers the following components:
|
||||
|
||||
* The Hubzilla core repository: https://framagit.org/hubzilla/core
|
||||
* The official addon repository: https://framagit.org/hubzilla/addons
|
||||
* The official themes repository: https://framagit.org/hubzilla/themes
|
||||
* The official widgets repository: https://framagit.org/hubzilla/widgets
|
||||
|
||||
## Coordinated Disclosure Guidelines
|
||||
|
||||
We are committed to working with security researchers to verify, reproduce, and respond to legitimate reported vulnerabilities. You can help us by following these simple guidelines:
|
||||
|
||||
* Submit suspected vulnerabilities by email to `security@hubzilla.org`, or as a confidential issue in the relevant repository listed above.
|
||||
* Provide clear instructions on how to reproduce the issue, and if possible, a minimal Proof of Concept (PoC) exploit.
|
||||
* We will acknowledge your submission as soon as we can, and will keep you updated as it is being processed. We may ask for more information, or clarifications about the issue or the steps to reproduce it during this time.
|
||||
* We will assign a CVE to the issue once it is confirmed.
|
||||
* We will do our best to fix the issue as soon as we can after it has been confirmed. We request that information about the vulnerability or details about how to exploit it is not disclosed to other parties until after the fix is released and some time has passed, to allow site administrators to upgrade. We will normally make the CVE public one month after a fix has been released. (This grace period can differ based on severity, and can be negotiated.)
|
||||
* Please perform all tests against a local instance of the software, and refrain from running any Denial of Service or automated testing tools against public hubs or the project managers (and their partners') infrastructure.
|
||||
* If the issue belongs to a third party module that we depend on, we may help with reporting it upstream if the submitter wants us to.
|
||||
|
||||
## Comments on this Policy
|
||||
|
||||
We welcome comments and suggestions for improving this policy. You can reach us at:
|
||||
|
||||
* Our ticketing system: https://framagit.org/hubzilla/core/-/issues
|
||||
* By sending us an email at `security@hubzilla.org`.
|
||||
|
||||
[Hubzilla]: https://hubzilla.org
|
||||
@@ -11,15 +11,18 @@ class Importdoc {
|
||||
|
||||
self::update_docs_dir('doc/*');
|
||||
|
||||
$sys = get_sys_channel();
|
||||
|
||||
// remove old files that weren't updated (indicates they were most likely deleted).
|
||||
$i = q("select id, uid from item where item_type = 5 and edited < %s - INTERVAL %s",
|
||||
$i = q("select id from item where uid = %d and item_type = 5 and edited < %s - INTERVAL %s",
|
||||
intval($sys['channel_id']),
|
||||
db_utcnow(),
|
||||
db_quoteinterval('14 DAY')
|
||||
);
|
||||
|
||||
if ($i) {
|
||||
foreach ($i as $iv) {
|
||||
drop_item($iv['id'], uid: $iv['uid']);
|
||||
drop_item($iv['id'], uid: $sys['channel_id']);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -616,6 +616,7 @@ class Activity {
|
||||
if (!empty($cnv)) {
|
||||
if (is_string($cnv) && str_starts_with($cnv, z_root())) {
|
||||
$cnv = str_replace(['/item/', '/activity/'], ['/conversation/', '/conversation/'], $cnv);
|
||||
$ret['contextHistory'] = $cnv;
|
||||
}
|
||||
$ret['context'] = $cnv;
|
||||
}
|
||||
@@ -802,7 +803,7 @@ class Activity {
|
||||
|
||||
$ret = [];
|
||||
|
||||
if (isset($item['attachment'])) {
|
||||
if (isset($item['attachment']) && is_array($item['attachment'])) {
|
||||
$ptr = $item['attachment'];
|
||||
if (!array_key_exists(0, $ptr)) {
|
||||
$ptr = [$ptr];
|
||||
@@ -1050,6 +1051,7 @@ class Activity {
|
||||
if (!empty($cnv)) {
|
||||
if (is_string($cnv) && str_starts_with($cnv, z_root())) {
|
||||
$cnv = str_replace(['/item/', '/activity/'], ['/conversation/', '/conversation/'], $cnv);
|
||||
$ret['contextHistory'] = $cnv;
|
||||
}
|
||||
$ret['context'] = $cnv;
|
||||
}
|
||||
@@ -1716,9 +1718,9 @@ class Activity {
|
||||
return;
|
||||
}
|
||||
|
||||
$name = $person_obj['name'] ?? '';
|
||||
$name = ((isset($person_obj['name'])) ? escape_tags($person_obj['name']) : '');
|
||||
if (!$name) {
|
||||
$name = $person_obj['preferredUsername'] ?? '';
|
||||
$name = ((isset($person_obj['preferredUsername'])) ? escape_tags($person_obj['preferredUsername']) : '');
|
||||
}
|
||||
if (!$name) {
|
||||
$name = t('Unknown');
|
||||
@@ -1727,13 +1729,11 @@ class Activity {
|
||||
$webfinger_addr = ((isset($person_obj['webfinger'])) ? str_replace('acct:', '', $person_obj['webfinger']) : '');
|
||||
$hostname = '';
|
||||
$baseurl = '';
|
||||
$site_url = '';
|
||||
|
||||
$m = parse_url($url);
|
||||
if ($m) {
|
||||
$hostname = $m['host'];
|
||||
$baseurl = $m['scheme'] . '://' . $m['host'] . ((isset($m['port'])) ? ':' . $m['port'] : '');
|
||||
$site_url = $m['scheme'] . '://' . $m['host'];
|
||||
$hostname = unparse_url($m, ['host']);
|
||||
$baseurl = unparse_url($m, ['scheme', 'host', 'port']);
|
||||
}
|
||||
|
||||
if (!$webfinger_addr && !empty($person_obj['preferredUsername']) && $hostname) {
|
||||
@@ -1835,7 +1835,7 @@ class Activity {
|
||||
|
||||
q("UPDATE site SET site_update = '%s', site_dead = 0 WHERE site_url = '%s'",
|
||||
dbesc(datetime_convert()),
|
||||
dbesc($site_url)
|
||||
dbesc($baseurl)
|
||||
);
|
||||
|
||||
// update existing xchan record
|
||||
@@ -2974,7 +2974,10 @@ class Activity {
|
||||
// This isn't perfect but the best we can do for now.
|
||||
$item['comment_policy'] = ((isset($act->data['commentPolicy'])) ? $act->data['commentPolicy'] : 'authenticated');
|
||||
|
||||
if (!empty($act->obj['context'])) {
|
||||
if (!empty($act->obj['contextHistory'])) {
|
||||
IConfig::Set($item, 'activitypub', 'context', $act->obj['contextHistory'], 1);
|
||||
}
|
||||
elseif (!empty($act->obj['context'])) {
|
||||
IConfig::Set($item, 'activitypub', 'context', $act->obj['context'], 1);
|
||||
}
|
||||
|
||||
@@ -3694,6 +3697,8 @@ class Activity {
|
||||
|
||||
return [
|
||||
'zot' => z_root() . '/apschema#',
|
||||
|
||||
'contextHistory' => 'https://w3id.org/fep/171b/contextHistory',
|
||||
'schema' => 'http://schema.org#',
|
||||
'ostatus' => 'http://ostatus.org#',
|
||||
'diaspora' => 'https://diasporafoundation.org/ns/',
|
||||
@@ -3717,7 +3722,6 @@ class Activity {
|
||||
|
||||
'manuallyApprovesFollowers' => 'as:manuallyApprovesFollowers',
|
||||
'Hashtag' => 'as:Hashtag'
|
||||
|
||||
];
|
||||
|
||||
}
|
||||
|
||||
@@ -24,10 +24,16 @@ class Connect {
|
||||
|
||||
$uid = $channel['channel_id'];
|
||||
|
||||
if (strpos($url,'@') === false && strpos($url,'/') === false) {
|
||||
// If we get just a channel name and it is not an URL turn it into a local webbie
|
||||
if (!str_contains($url, '@') && strpos($url,'/') === false) {
|
||||
$url = $url . '@' . App::get_hostname();
|
||||
}
|
||||
|
||||
// Remove a possible leading @
|
||||
if (str_starts_with($url, '@')) {
|
||||
$url = ltrim($url, '@');
|
||||
}
|
||||
|
||||
$result = [ 'success' => false, 'message' => '' ];
|
||||
|
||||
$my_perms = false;
|
||||
|
||||
@@ -213,28 +213,36 @@ class Enotify {
|
||||
//$possess_desc = str_replace('<!item_type!>',$possess_desc);
|
||||
|
||||
// "a post"
|
||||
$dest_str = sprintf(t('%1$s %2$s [zrl=%3$s]a %4$s[/zrl]'),
|
||||
$dest_str = sprintf(
|
||||
t('%1$s %2$s [zrl=%3$s]a %4$s[/zrl]'),
|
||||
'[zrl=' . $sender['xchan_url'] . ']' . $sender['xchan_name'] . '[/zrl]',
|
||||
$action,
|
||||
$itemlink,
|
||||
$item_post_type);
|
||||
$item_post_type
|
||||
);
|
||||
|
||||
// "George Bull's post"
|
||||
if($p)
|
||||
$dest_str = sprintf(t('%1$s %2$s [zrl=%3$s]%4$s\'s %5$s[/zrl]'),
|
||||
if($p) {
|
||||
$dest_str = sprintf(
|
||||
t('%1$s %2$s [zrl=%3$s]%4$s\'s %5$s[/zrl]'),
|
||||
'[zrl=' . $sender['xchan_url'] . ']' . $sender['xchan_name'] . '[/zrl]',
|
||||
$action,
|
||||
$itemlink,
|
||||
$p[0]['author']['xchan_name'],
|
||||
$item_post_type);
|
||||
$parent_item['author']['xchan_name'],
|
||||
$item_post_type
|
||||
);
|
||||
}
|
||||
|
||||
// "your post"
|
||||
if($p[0]['owner']['xchan_name'] == $p[0]['author']['xchan_name'] && intval($p[0]['item_wall']))
|
||||
$dest_str = sprintf(t('%1$s %2$s [zrl=%3$s]your %4$s[/zrl]'),
|
||||
if ($parent_item['owner']['xchan_hash'] === $recip['channel_hash'] && intval($parent_item['item_wall'])) {
|
||||
$dest_str = sprintf(
|
||||
t('%1$s %2$s [zrl=%3$s]your %4$s[/zrl]'),
|
||||
'[zrl=' . $sender['xchan_url'] . ']' . $sender['xchan_name'] . '[/zrl]',
|
||||
$action,
|
||||
$itemlink,
|
||||
$item_post_type);
|
||||
$item_post_type
|
||||
);
|
||||
}
|
||||
|
||||
// Some mail softwares relies on subject field for threading.
|
||||
// So, we cannot have different subjects for notifications of the same thread.
|
||||
@@ -308,7 +316,6 @@ class Enotify {
|
||||
$item_post_type = item_post_type($p[0]);
|
||||
// $private = $p[0]['item_private'];
|
||||
$parent_id = $p[0]['id'];
|
||||
|
||||
$parent_item = $p[0];
|
||||
|
||||
//$verb = ((activity_match($params['item']['verb'], ACTIVITY_DISLIKE)) ? t('disliked') : t('liked'));
|
||||
@@ -321,13 +328,14 @@ class Enotify {
|
||||
$verb = (($moderated) ? t('requested to dislike') : t('disliked'));
|
||||
|
||||
// "your post"
|
||||
if($p[0]['owner']['xchan_name'] === $p[0]['author']['xchan_name'] && intval($p[0]['item_wall']))
|
||||
if ($parent_item['author']['xchan_hash'] === $recip['channel_hash']) {
|
||||
$dest_str = sprintf(t('%1$s %2$s [zrl=%3$s]your %4$s[/zrl]'),
|
||||
'[zrl=' . $sender['xchan_url'] . ']' . $sender['xchan_name'] . '[/zrl]',
|
||||
$verb,
|
||||
$itemlink,
|
||||
$item_post_type
|
||||
);
|
||||
}
|
||||
else {
|
||||
pop_lang();
|
||||
return;
|
||||
|
||||
@@ -1561,7 +1561,7 @@ class Libzot {
|
||||
|
||||
$conversation_operation = $is_collection_operation && isset($arr['target']['attributedTo']);
|
||||
|
||||
if (str_contains($arr['tgt_type'], 'Collection') && !$relay && !$conversation_operation) {
|
||||
if (isset($arr['tgt_type']) && str_contains($arr['tgt_type'], 'Collection') && !$relay && !$conversation_operation) {
|
||||
$DR->update('not a collection activity');
|
||||
$result[] = $DR->get();
|
||||
continue;
|
||||
|
||||
@@ -799,6 +799,7 @@ class ThreadItem {
|
||||
'$submit' => t('Submit'),
|
||||
'$edbold' => t('Bold'),
|
||||
'$editalic' => t('Italic'),
|
||||
'$edhighlighter' => t('Highlight selected text'),
|
||||
'$eduline' => t('Underline'),
|
||||
'$edquote' => t('Quote'),
|
||||
'$edcode' => t('Code'),
|
||||
|
||||
@@ -30,7 +30,7 @@ class Activity extends Controller {
|
||||
dbesc(ACTIVITY_UNFOLLOW)
|
||||
);
|
||||
|
||||
$item_normal = " and item.item_hidden = 0 and item.item_type = 0 and item.item_unpublished = 0 and item.item_delayed = 0 and item.item_blocked = 0 $item_normal_extra ";
|
||||
$item_normal = " and item.item_hidden = 0 and item.item_type = 0 and item.item_unpublished = 0 and item.item_delayed = 0 and item.item_blocked = 0 and item.item_uplink = 0 $item_normal_extra ";
|
||||
|
||||
$i = null;
|
||||
|
||||
@@ -191,7 +191,7 @@ class Activity extends Controller {
|
||||
dbesc(ACTIVITY_UNFOLLOW)
|
||||
);
|
||||
|
||||
$item_normal = " and item.item_hidden = 0 and item.item_type = 0 and item.item_unpublished = 0 and item.item_delayed = 0 and item.item_blocked = 0 $item_normal_extra ";
|
||||
$item_normal = " and item.item_hidden = 0 and item.item_type = 0 and item.item_unpublished = 0 and item.item_delayed = 0 and item.item_blocked = 0 and item.item_uplink = 0 $item_normal_extra ";
|
||||
|
||||
$sigdata = HTTPSig::verify(EMPTY_STR);
|
||||
if ($sigdata['portable_id'] && $sigdata['header_valid']) {
|
||||
|
||||
@@ -30,7 +30,7 @@ class Conversation extends Controller {
|
||||
dbesc(ACTIVITY_UNFOLLOW)
|
||||
);
|
||||
|
||||
$item_normal = " and item.item_hidden = 0 and item.item_type = 0 and item.item_unpublished = 0 and item.item_delayed = 0 and item.item_blocked = 0 $item_normal_extra ";
|
||||
$item_normal = " and item.item_hidden = 0 and item.item_type = 0 and item.item_unpublished = 0 and item.item_delayed = 0 and item.item_blocked = 0 and item.item_uplink = 0 $item_normal_extra ";
|
||||
|
||||
$i = null;
|
||||
|
||||
@@ -83,9 +83,9 @@ class Conversation extends Controller {
|
||||
// if we don't have a parent id belonging to the signer see if we can obtain one as a visitor that we have permission to access
|
||||
// with a bias towards those items owned by channels on this site (item_wall = 1)
|
||||
|
||||
$sql_extra = item_permissions_sql(0);
|
||||
|
||||
if (!$i) {
|
||||
$sql_extra = item_permissions_sql(0);
|
||||
|
||||
$i = q("select id as item_id from item where mid = '%s' $item_normal $sql_extra order by item_wall desc limit 1",
|
||||
dbesc($r[0]['parent_mid'])
|
||||
);
|
||||
|
||||
@@ -100,14 +100,25 @@ class Home extends Controller {
|
||||
goaway($frontpage);
|
||||
}
|
||||
|
||||
$o .= '<div class="generic-content-wrapper">';
|
||||
|
||||
$sitename = Config::Get('system', 'sitename');
|
||||
if ($sitename)
|
||||
$o .= '<h1 class="home-welcome">' . sprintf(t('Welcome to %s'), $sitename) . '</h1>';
|
||||
if ($sitename) {
|
||||
$o .= '<div class="section-title-wrapper">';
|
||||
$o .= '<h2 class="">' . sprintf(t('Welcome to %s'), $sitename) . '</h2>';
|
||||
$o .= '</div>';
|
||||
|
||||
}
|
||||
|
||||
$o .= '<div class="section-content-wrapper">';
|
||||
|
||||
$loginbox = Config::Get('system', 'login_on_homepage');
|
||||
if (intval($loginbox) || $loginbox === false)
|
||||
$o .= login(true);
|
||||
|
||||
$o .= '</div>';
|
||||
$o .= '</div>';
|
||||
|
||||
return $o;
|
||||
|
||||
}
|
||||
|
||||
@@ -383,6 +383,7 @@ class Item extends Controller {
|
||||
$r = q("select * from xchan where xchan_hash = '%s' limit 1",
|
||||
dbesc($channel['channel_hash'])
|
||||
);
|
||||
|
||||
if ($r && count($r)) {
|
||||
$owner_xchan = $r[0];
|
||||
}
|
||||
@@ -486,6 +487,7 @@ class Item extends Controller {
|
||||
$thr_parent = $orig_post['thr_parent'];
|
||||
$parent_mid = $orig_post['parent_mid'];
|
||||
$plink = $orig_post['plink'];
|
||||
$owner_hash = $orig_post['owner_xchan'];
|
||||
}
|
||||
else {
|
||||
if (!$walltowall) {
|
||||
@@ -821,28 +823,26 @@ class Item extends Controller {
|
||||
$mid = $mid ?? z_root() . '/item/' . $uuid;
|
||||
|
||||
|
||||
// Set the conversation target.
|
||||
if (empty($owner_hash)) {
|
||||
$owner_hash = $owner_xchan['xchan_hash'];
|
||||
}
|
||||
|
||||
if ($owner_hash === $channel['channel_hash']) {
|
||||
$attributedTo = z_root() . '/channel/' . $channel['channel_address'];
|
||||
|
||||
$conversation = isset($parent_item) ? $parent_item['mid'] : $mid;
|
||||
$datarray['target'] = [
|
||||
'id' => str_replace('/item/', '/conversation/', $conversation),
|
||||
'type' => 'Collection',
|
||||
'attributedTo' => $attributedTo,
|
||||
];
|
||||
$datarray['tgt_type'] = 'Collection';
|
||||
}
|
||||
elseif (!empty($parent_item['target'])) {
|
||||
$datarray['target'] = $parent_item['target'];
|
||||
$datarray['tgt_type'] = $parent_item['tgt_type'];
|
||||
}
|
||||
if (empty($owner_hash)) {
|
||||
$owner_hash = $owner_xchan['xchan_hash'];
|
||||
}
|
||||
|
||||
// Set the conversation target.
|
||||
if ($owner_hash === $channel['channel_hash']) {
|
||||
$attributedTo = z_root() . '/channel/' . $channel['channel_address'];
|
||||
|
||||
$conversation = isset($parent_item) ? $parent_item['mid'] : $mid;
|
||||
$datarray['target'] = [
|
||||
'id' => str_replace('/item/', '/conversation/', $conversation),
|
||||
'type' => 'Collection',
|
||||
'attributedTo' => $attributedTo,
|
||||
];
|
||||
$datarray['tgt_type'] = 'Collection';
|
||||
}
|
||||
elseif (!empty($parent_item['target'])) {
|
||||
$datarray['target'] = $parent_item['target'];
|
||||
$datarray['tgt_type'] = $parent_item['tgt_type'];
|
||||
}
|
||||
|
||||
if ($is_poll) {
|
||||
$poll = [
|
||||
@@ -1503,7 +1503,7 @@ class Item extends Controller {
|
||||
dbesc(ACTIVITY_UNFOLLOW)
|
||||
);
|
||||
|
||||
$item_normal = " and item.item_hidden = 0 and item.item_type = 0 and item.item_unpublished = 0 and item.item_delayed = 0 and item.item_blocked = 0 $item_normal_extra ";
|
||||
$item_normal = " and item.item_hidden = 0 and item.item_type = 0 and item.item_unpublished = 0 and item.item_delayed = 0 and item.item_blocked = 0 and item.item_uplink = 0 $item_normal_extra ";
|
||||
|
||||
$i = null;
|
||||
|
||||
@@ -1619,7 +1619,7 @@ class Item extends Controller {
|
||||
dbesc(ACTIVITY_UNFOLLOW)
|
||||
);
|
||||
|
||||
$item_normal = " and item.item_hidden = 0 and item.item_type = 0 and item.item_unpublished = 0 and item.item_delayed = 0 and item.item_blocked = 0 $item_normal_extra ";
|
||||
$item_normal = " and item.item_hidden = 0 and item.item_type = 0 and item.item_unpublished = 0 and item.item_delayed = 0 and item.item_blocked = 0 and item.item_uplink = 0 $item_normal_extra ";
|
||||
|
||||
$i = null;
|
||||
|
||||
|
||||
@@ -10,7 +10,16 @@ class Login extends \Zotlabs\Web\Controller {
|
||||
if(remote_channel() && $_SESSION['atoken'])
|
||||
goaway(z_root());
|
||||
|
||||
return login(true);
|
||||
$o = '<div class="generic-content-wrapper">';
|
||||
$o .= '<div class="section-title-wrapper">';
|
||||
$o .= '<h2 class="">' . t('Login') . '</h2>';
|
||||
$o .= '</div>';
|
||||
$o .= '<div class="section-content-wrapper">';
|
||||
$o .= login(true);
|
||||
$o .= '</div>';
|
||||
$o .= '</div>';
|
||||
|
||||
return $o;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -134,6 +134,15 @@ class Magic extends Controller {
|
||||
$args = (($x) ? '&owt=' . $token : '?owt=' . $token) . (($delegate) ? '&delegate=1' : '');
|
||||
goaway($dest . $args);
|
||||
}
|
||||
else {
|
||||
$o = '<h1>OWA ERROR</h1>';
|
||||
if (!empty($j['message'])) {
|
||||
$o .= '<h2>' . $j['message'] . '</h2>';
|
||||
}
|
||||
$o .= '<a href=' . $dest . '>' . $dest . '</a>';
|
||||
|
||||
echo $o;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,96 +18,95 @@ use Zotlabs\Web\Controller;
|
||||
|
||||
class Owa extends Controller {
|
||||
|
||||
function init() {
|
||||
public function init(): void
|
||||
{
|
||||
|
||||
$ret = [ 'success' => false ];
|
||||
|
||||
if (array_key_exists('REDIRECT_REMOTE_USER',$_SERVER) && (! array_key_exists('HTTP_AUTHORIZATION',$_SERVER))) {
|
||||
$_SERVER['HTTP_AUTHORIZATION'] = $_SERVER['REDIRECT_REMOTE_USER'];
|
||||
if (!$this->validateAuthorizationHeader()) {
|
||||
$this->error('Missing or invalid authorization header.');
|
||||
}
|
||||
|
||||
if (array_key_exists('HTTP_AUTHORIZATION',$_SERVER) && substr(trim($_SERVER['HTTP_AUTHORIZATION']),0,9) === 'Signature') {
|
||||
$sigblock = HTTPSig::parse_sigheader($_SERVER['HTTP_AUTHORIZATION']);
|
||||
if ($sigblock) {
|
||||
$keyId = $sigblock['keyId'];
|
||||
$parsed = parse_url($keyId);
|
||||
if (str_starts_with($parsed['scheme'],'http')) {
|
||||
unset($parsed['fragment']);
|
||||
unset($parsed['query']);
|
||||
$keyId = unparse_url($parsed);
|
||||
$sigblock = HTTPSig::parse_sigheader($_SERVER['HTTP_AUTHORIZATION']);
|
||||
if ($sigblock) {
|
||||
$keyId = $sigblock['keyId'];
|
||||
$parsed = parse_url($keyId);
|
||||
if (str_starts_with($parsed['scheme'],'http')) {
|
||||
unset($parsed['fragment']);
|
||||
unset($parsed['query']);
|
||||
$keyId = unparse_url($parsed);
|
||||
}
|
||||
else {
|
||||
$keyId = str_replace('acct:', '', $keyId);
|
||||
}
|
||||
if ($keyId) {
|
||||
$r = q("SELECT * FROM hubloc LEFT JOIN xchan ON hubloc_hash = xchan_hash
|
||||
WHERE (hubloc_addr = '%s' OR hubloc_id_url = '%s' OR xchan_hash = '%s')
|
||||
AND hubloc_deleted = 0 AND xchan_pubkey != ''
|
||||
ORDER BY hubloc_id DESC",
|
||||
dbesc($keyId),
|
||||
dbesc($keyId),
|
||||
dbesc($keyId)
|
||||
);
|
||||
if (! $r) {
|
||||
$found = discover_by_webbie($keyId);
|
||||
logger('found = ' . print_r($found, true));
|
||||
if ($found) {
|
||||
$r = q("SELECT * FROM hubloc LEFT JOIN xchan ON hubloc_hash = xchan_hash
|
||||
WHERE (hubloc_addr = '%s' OR hubloc_id_url = '%s' OR xchan_hash = '%s') AND hubloc_deleted = 0 AND xchan_pubkey != '' ORDER BY hubloc_id DESC ",
|
||||
dbesc($keyId),
|
||||
dbesc($keyId),
|
||||
dbesc($keyId)
|
||||
);
|
||||
}
|
||||
}
|
||||
else {
|
||||
$keyId = str_replace('acct:', '', $keyId);
|
||||
}
|
||||
if ($keyId) {
|
||||
$r = q("SELECT * FROM hubloc LEFT JOIN xchan ON hubloc_hash = xchan_hash
|
||||
WHERE (hubloc_addr = '%s' OR hubloc_id_url = '%s' OR xchan_hash = '%s')
|
||||
AND hubloc_deleted = 0 AND xchan_pubkey != ''
|
||||
ORDER BY hubloc_id DESC",
|
||||
dbesc($keyId),
|
||||
dbesc($keyId),
|
||||
dbesc($keyId)
|
||||
);
|
||||
if (! $r) {
|
||||
$found = discover_by_webbie($keyId);
|
||||
logger('found = ' . print_r($found, true));
|
||||
if ($found) {
|
||||
$r = q("SELECT * FROM hubloc LEFT JOIN xchan ON hubloc_hash = xchan_hash
|
||||
WHERE (hubloc_addr = '%s' OR hubloc_id_url = '%s' OR xchan_hash = '%s') AND hubloc_deleted = 0 AND xchan_pubkey != '' ORDER BY hubloc_id DESC ",
|
||||
dbesc($keyId),
|
||||
dbesc($keyId),
|
||||
dbesc($keyId)
|
||||
);
|
||||
|
||||
if ($r) {
|
||||
foreach ($r as $hubloc) {
|
||||
$verified = HTTPSig::verify(file_get_contents('php://input'), $hubloc['xchan_pubkey']);
|
||||
if ($verified && $verified['header_signed'] && $verified['header_valid'] && ($verified['content_valid'] || (! $verified['content_signed']))) {
|
||||
logger('OWA header: ' . print_r($verified,true),LOGGER_DATA);
|
||||
logger('OWA success: ' . $hubloc['hubloc_id_url'],LOGGER_DATA);
|
||||
$ret['success'] = true;
|
||||
$token = random_string(32);
|
||||
Verify::create('owt',0,$token,$hubloc['hubloc_id_url']);
|
||||
$result = '';
|
||||
openssl_public_encrypt($token,$result,$hubloc['xchan_pubkey']);
|
||||
$ret['encrypted_token'] = base64url_encode($result);
|
||||
break;
|
||||
} else {
|
||||
logger('OWA fail: ' . $hubloc['hubloc_id'] . ' ' . $hubloc['hubloc_id_url']);
|
||||
}
|
||||
}
|
||||
|
||||
if ($r) {
|
||||
foreach ($r as $hubloc) {
|
||||
$verified = HTTPSig::verify(file_get_contents('php://input'), $hubloc['xchan_pubkey']);
|
||||
if ($verified && $verified['header_signed'] && $verified['header_valid'] && ($verified['content_valid'] || (! $verified['content_signed']))) {
|
||||
logger('OWA header: ' . print_r($verified,true),LOGGER_DATA);
|
||||
logger('OWA success: ' . $hubloc['hubloc_id_url'],LOGGER_DATA);
|
||||
$ret['success'] = true;
|
||||
$token = random_string(32);
|
||||
Verify::create('owt',0,$token,$hubloc['hubloc_id_url']);
|
||||
$result = '';
|
||||
openssl_public_encrypt($token,$result,$hubloc['xchan_pubkey']);
|
||||
$ret['encrypted_token'] = base64url_encode($result);
|
||||
break;
|
||||
} else {
|
||||
logger('OWA fail: ' . $hubloc['hubloc_id'] . ' ' . $hubloc['hubloc_id_url']);
|
||||
}
|
||||
}
|
||||
if (!$ret['success']) {
|
||||
|
||||
if (!$ret['success']) {
|
||||
// Possible a reinstall?
|
||||
// In this case we probably already have an old hubloc
|
||||
// but not the new one yet.
|
||||
|
||||
// Possible a reinstall?
|
||||
// In this case we probably already have an old hubloc
|
||||
// but not the new one yet.
|
||||
$found = discover_by_webbie($keyId);
|
||||
|
||||
$found = discover_by_webbie($keyId);
|
||||
if ($found) {
|
||||
$r = q("SELECT * FROM hubloc LEFT JOIN xchan ON hubloc_hash = xchan_hash
|
||||
WHERE (hubloc_addr = '%s' OR hubloc_id_url = '%s') AND hubloc_deleted = 0 ORDER BY hubloc_id DESC LIMIT 1",
|
||||
dbesc(str_replace('acct:', '', $keyId)),
|
||||
dbesc($keyId)
|
||||
);
|
||||
|
||||
if ($found) {
|
||||
$r = q("SELECT * FROM hubloc LEFT JOIN xchan ON hubloc_hash = xchan_hash
|
||||
WHERE (hubloc_addr = '%s' OR hubloc_id_url = '%s') AND hubloc_deleted = 0 ORDER BY hubloc_id DESC LIMIT 1",
|
||||
dbesc(str_replace('acct:', '', $keyId)),
|
||||
dbesc($keyId)
|
||||
);
|
||||
|
||||
if ($r) {
|
||||
$verified = HTTPSig::verify(file_get_contents('php://input'), $r[0]['xchan_pubkey']);
|
||||
if ($verified && $verified['header_signed'] && $verified['header_valid'] && ($verified['content_valid'] || (! $verified['content_signed']))) {
|
||||
logger('OWA header: ' . print_r($verified,true), LOGGER_DATA);
|
||||
logger('OWA success: ' . $r[0]['hubloc_id_url'], LOGGER_DATA);
|
||||
$ret['success'] = true;
|
||||
$token = random_string(32);
|
||||
Verify::create('owt', 0, $token, $r[0]['hubloc_id_url']);
|
||||
$result = '';
|
||||
openssl_public_encrypt($token, $result, $r[0]['xchan_pubkey']);
|
||||
$ret['encrypted_token'] = base64url_encode($result);
|
||||
} else {
|
||||
logger('OWA fail: ' . $hubloc['hubloc_id'] . ' ' . $hubloc['hubloc_id_url']);
|
||||
}
|
||||
if ($r) {
|
||||
$verified = HTTPSig::verify(file_get_contents('php://input'), $r[0]['xchan_pubkey']);
|
||||
if ($verified && $verified['header_signed'] && $verified['header_valid'] && ($verified['content_valid'] || (! $verified['content_signed']))) {
|
||||
logger('OWA header: ' . print_r($verified,true), LOGGER_DATA);
|
||||
logger('OWA success: ' . $r[0]['hubloc_id_url'], LOGGER_DATA);
|
||||
$ret['success'] = true;
|
||||
$token = random_string(32);
|
||||
Verify::create('owt', 0, $token, $r[0]['hubloc_id_url']);
|
||||
$result = '';
|
||||
openssl_public_encrypt($token, $result, $r[0]['xchan_pubkey']);
|
||||
$ret['encrypted_token'] = base64url_encode($result);
|
||||
} else {
|
||||
logger('OWA fail: ' . $hubloc['hubloc_id'] . ' ' . $hubloc['hubloc_id_url']);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -118,4 +117,33 @@ class Owa extends Controller {
|
||||
|
||||
json_return_and_die($ret,'application/x-zot+json');
|
||||
}
|
||||
|
||||
private function validateAuthorizationHeader(): bool
|
||||
{
|
||||
if (!empty($_SERVER['HTTP_AUTHORIZATION'])) {
|
||||
$auth = trim($_SERVER['HTTP_AUTHORIZATION']);
|
||||
} else if (!empty($_SERVER['REDIRECT_REMOTE_USER'])) {
|
||||
$auth = trim($_SERVER['REDIRECT_REMOTE_USER']);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
return strncmp($auth, 'Signature', 9) === 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Terminates the request, and return a json error response.
|
||||
*
|
||||
* @Note This function does not return!
|
||||
*
|
||||
* @param string $msg The error message for the response.
|
||||
*/
|
||||
private function error(string $msg): void {
|
||||
$ret = [
|
||||
'success' => false,
|
||||
'message' => $msg
|
||||
];
|
||||
|
||||
json_return_and_die($ret,'application/x-zot+json');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -207,7 +207,7 @@ class Sse_bs extends Controller {
|
||||
$item_normal
|
||||
$sql_extra
|
||||
$sql_extra2
|
||||
ORDER BY created DESC LIMIT $limit OFFSET $offset",
|
||||
ORDER BY created DESC, received DESC LIMIT $limit OFFSET $offset",
|
||||
intval(self::$uid),
|
||||
dbescdate($_SESSION['sse_loadtime']),
|
||||
dbesc(self::$ob_hash)
|
||||
@@ -290,7 +290,7 @@ class Sse_bs extends Controller {
|
||||
$item_normal
|
||||
$sql_extra
|
||||
$sql_extra2
|
||||
ORDER BY created DESC LIMIT $limit OFFSET $offset",
|
||||
ORDER BY created DESC, received DESC LIMIT $limit OFFSET $offset",
|
||||
intval(self::$uid),
|
||||
dbescdate($_SESSION['sse_loadtime']),
|
||||
dbesc(self::$ob_hash)
|
||||
@@ -373,7 +373,7 @@ class Sse_bs extends Controller {
|
||||
$item_normal
|
||||
$sql_extra
|
||||
$sql_extra2
|
||||
ORDER BY created DESC LIMIT $limit OFFSET $offset",
|
||||
ORDER BY created DESC, received DESC LIMIT $limit OFFSET $offset",
|
||||
intval(self::$uid),
|
||||
dbescdate($_SESSION['sse_loadtime']),
|
||||
dbesc(self::$ob_hash)
|
||||
@@ -481,7 +481,7 @@ class Sse_bs extends Controller {
|
||||
$sql_extra
|
||||
$sql_extra2
|
||||
$sql_extra3
|
||||
ORDER BY created DESC LIMIT $limit OFFSET $offset",
|
||||
ORDER BY created DESC, received DESC LIMIT $limit OFFSET $offset",
|
||||
dbescdate($_SESSION['sse_loadtime']),
|
||||
dbesc(self::$ob_hash),
|
||||
dbescdate($_SESSION['last_login_date'] ?? $_SESSION['static_loadtime'])
|
||||
@@ -679,7 +679,7 @@ class Sse_bs extends Controller {
|
||||
AND author_xchan != '%s'
|
||||
AND item_unseen = 1
|
||||
$item_normal
|
||||
ORDER BY created DESC",
|
||||
ORDER BY created DESC, received DESC",
|
||||
dbesc(ACTIVITY_POST),
|
||||
intval(self::$uid),
|
||||
dbesc(self::$ob_hash)
|
||||
|
||||
@@ -15,13 +15,19 @@ class Zot_probe extends \Zotlabs\Web\Controller {
|
||||
|
||||
$o .= '<form action="zot_probe" method="get">';
|
||||
$o .= 'Lookup URI: <input type="text" style="width: 250px;" name="addr" value="' . $addr .'" /><br>';
|
||||
$o .= '<input type="checkbox" name="sign" /> Sign request <br>';
|
||||
$o .= '<input type="submit" name="submit" value="Submit" /></form>';
|
||||
|
||||
$o .= '<br /><br />';
|
||||
|
||||
if($addr) {
|
||||
|
||||
$x = Zotfinger::exec($addr);
|
||||
$channel = null;
|
||||
if ($_GET['sign']) {
|
||||
$channel = get_sys_channel();
|
||||
}
|
||||
|
||||
$x = Zotfinger::exec($addr, $channel);
|
||||
|
||||
$o .= '<pre>' . htmlspecialchars(print_array($x)) . '</pre>';
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace Zotlabs\Render;
|
||||
|
||||
use Smarty;
|
||||
use Smarty\Smarty;
|
||||
use App;
|
||||
|
||||
class SmartyInterface extends Smarty {
|
||||
@@ -26,13 +26,13 @@ class SmartyInterface extends Smarty {
|
||||
$this->setTemplateDir($template_dirs);
|
||||
|
||||
$basecompiledir = App::$config['system']['smarty3_folder'];
|
||||
|
||||
|
||||
$this->setCompileDir($basecompiledir.'/compiled/');
|
||||
$this->setConfigDir($basecompiledir.'/config/');
|
||||
$this->setCacheDir($basecompiledir.'/cache/');
|
||||
|
||||
$this->left_delimiter = App::get_template_ldelim('smarty3');
|
||||
$this->right_delimiter = App::get_template_rdelim('smarty3');
|
||||
$this->setLeftDelimiter(App::get_template_ldelim('smarty3'));
|
||||
$this->setRightDelimiter(App::get_template_rdelim('smarty3'));
|
||||
|
||||
// Don't report errors so verbosely
|
||||
$this->error_reporting = E_ALL & ~E_WARNING & ~E_NOTICE;
|
||||
|
||||
@@ -2,8 +2,11 @@
|
||||
|
||||
namespace Zotlabs\Thumbs;
|
||||
|
||||
use SebLucas\EPubMeta\EPub;
|
||||
use DOMDocument;
|
||||
use DOMElement;
|
||||
use DOMXPath;
|
||||
use GdImage;
|
||||
use ZipArchive;
|
||||
|
||||
/**
|
||||
* Thumbnail creation for epub files.
|
||||
@@ -24,20 +27,21 @@ class Epubthumb {
|
||||
* Create the thumbnail if the Epub has a cover.
|
||||
*
|
||||
* @param array $attach
|
||||
* @param number $preview_style unused
|
||||
* @param number $height (optional) default 300
|
||||
* @param number $width (optional) default 300
|
||||
* @param int $preview_style unused
|
||||
* @param int $height (optional) default 300
|
||||
* @param int $width (optional) default 300
|
||||
*
|
||||
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
|
||||
* phpcs:disable Generic.CodeAnalysis.UnusedFunctionParameter.FoundBeforeLastUsed
|
||||
*/
|
||||
function Thumb($attach, $preview_style, $height = 300, $width = 300) {
|
||||
function Thumb($attach, $preview_style, $height = 300, $width = 300): void {
|
||||
|
||||
$file = dbunescbin($attach['content']);
|
||||
if (!$file) {
|
||||
return;
|
||||
}
|
||||
|
||||
$image = $this->getCover($file);
|
||||
$image = $this->getCoverFromEpub($file);
|
||||
|
||||
if ($image) {
|
||||
$srcwidth = imagesx($image);
|
||||
@@ -56,15 +60,139 @@ class Epubthumb {
|
||||
}
|
||||
}
|
||||
|
||||
private function getCover(string $filename): GdImage|false {
|
||||
$epub = new EPub($filename);
|
||||
$cover = $epub->getCover();
|
||||
/**
|
||||
* Fetch the cover from the epub archive, if it's present.
|
||||
*
|
||||
* There's a few limitations here: This will only work if the cover
|
||||
* is a raster image of a supported format. SVG does not work, neither
|
||||
* will other schemes sometimes used for cover/front page.
|
||||
*
|
||||
* @param string $filename The local filename of the epub archive.
|
||||
*
|
||||
* @return GdImage|false If a cover is found, it is returned as a
|
||||
* GdImage object. Otherwise return false.
|
||||
*/
|
||||
private function getCoverFromEpub(string $filename): GdImage|false {
|
||||
$epub = new ZipArchive();
|
||||
$rc = $epub->open($filename, ZipArchive::RDONLY);
|
||||
|
||||
if (! empty($cover)) {
|
||||
if ($rc !== true) {
|
||||
logger("Error opening file '{$filename}': rc = ${rc}.", LOGGER_DEBUG, LOG_DEBUG);
|
||||
return false;
|
||||
}
|
||||
|
||||
$cover = false;
|
||||
$cover_name = $this->parseEpub($epub);
|
||||
if ($cover_name !== false) {
|
||||
$cover = $epub->getFromName($cover_name);
|
||||
if ($cover === false) {
|
||||
logger("File '{$cover_name}' not found in EPUB.", LOGGER_DEBUG, LOG_DEBUG);
|
||||
}
|
||||
}
|
||||
|
||||
$epub->close();
|
||||
|
||||
if ($cover !== false && !empty($cover)) {
|
||||
return imagecreatefromstring($cover);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the epub to find the path of the cover image.
|
||||
*
|
||||
* @param ZipArchive $epub An opened epub ZipArchive.
|
||||
*
|
||||
* @return string|false The path to the cover image or false.
|
||||
*/
|
||||
private function parseEpub(ZipArchive $epub): string|false {
|
||||
$packagePath = $this->getEpubPackagePath($epub);
|
||||
if ($packagePath !== false) {
|
||||
$package = $epub->getFromName($packagePath);
|
||||
if ($package === false || empty($package)) {
|
||||
logger("Package file '${packagePath}' not found in EPUB", LOGGER_DEBUG, LOG_DEBUG);
|
||||
return false;
|
||||
}
|
||||
|
||||
$domdoc = new DOMDocument();
|
||||
$domdoc->loadXML($package);
|
||||
$xpath = new DOMXPath($domdoc);
|
||||
$xpath->registerNamespace("n", "http://www.idpf.org/2007/opf");
|
||||
$nodes = $xpath->query('/n:package/n:manifest/n:item[@properties="cover-image"]');
|
||||
|
||||
if ($nodes->count() === 0) {
|
||||
logger('No cover found in EPUB manifest.', LOGGER_DEBUG, LOG_DEBUG);
|
||||
return false;
|
||||
}
|
||||
|
||||
$node = $nodes->item(0);
|
||||
if ($node === null) {
|
||||
logger('No nodes in non-empty node list?', LOGGER_DEBUG, LOG_DEBUG);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (is_a($node, DOMElement::class)) {
|
||||
// The URL's in the package file is relative to the subdirectory
|
||||
// within the epub archive where it is located. See
|
||||
// https://www.w3.org/TR/epub-33/#sec-parsing-urls-metainf
|
||||
return dirname($packagePath) . '/' . $node->getAttribute('href');
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Locate the package file within the epub.
|
||||
*
|
||||
* The package file in an epub archive contains the manifest
|
||||
* that again may contain a reference to the cover for the
|
||||
* epub.
|
||||
*
|
||||
* @param ZipArchive $epub An opened epub archive.
|
||||
*
|
||||
* @return string|false The full pathname of the package file or false.
|
||||
*/
|
||||
private function getEpubPackagePath(ZipArchive $epub): string|false {
|
||||
//
|
||||
// The only mandatory known file within the archive is the
|
||||
// container file, so we fetch it to find the reference to
|
||||
// the package file.
|
||||
//
|
||||
// See: https://www.w3.org/TR/epub-33/#sec-container-metainf
|
||||
//
|
||||
$container = $epub->getFromName('META-INF/container.xml');
|
||||
|
||||
if ($container === false || empty($container)) {
|
||||
logger('No container in archive, probably not an EPUB.', LOGGER_DEBUG, LOG_DEBUG);
|
||||
return false;
|
||||
}
|
||||
|
||||
$domdoc = new DOMDocument();
|
||||
$domdoc->loadXML($container);
|
||||
$nodes = $domdoc->getElementsByTagName('rootfile');
|
||||
|
||||
if ($nodes->count() == 0) {
|
||||
logger('EPUB rootfile not found, is this an epub?', LOGGER_DEBUG, LOG_DEBUG);
|
||||
return false;
|
||||
}
|
||||
|
||||
$packageNode = $nodes->item(0);
|
||||
if ($packageNode === null || !is_a($packageNode, DOMElement::class)) {
|
||||
logger('EPUB rootfile element missing or invalid.', LOGGER_DEBUG, LOG_DEBUG);
|
||||
return false;
|
||||
}
|
||||
|
||||
$packagePath = $packageNode->getAttribute('full-path');
|
||||
$packageMediaType = $packageNode->getAttribute('media-type');
|
||||
|
||||
if (empty($packagePath) || $packageMediaType !== 'application/oebps-package+xml') {
|
||||
logger('EPUB package path missing or incorrect media type.', LOGGER_DEBUG, LOG_DEBUG);
|
||||
return false;
|
||||
}
|
||||
|
||||
return $packagePath;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
4
boot.php
4
boot.php
@@ -66,7 +66,7 @@ require_once('include/security.php');
|
||||
|
||||
|
||||
define('PLATFORM_NAME', 'hubzilla');
|
||||
define('STD_VERSION', '10.0.7');
|
||||
define('STD_VERSION', '10.2');
|
||||
define('ZOT_REVISION', '6.0');
|
||||
|
||||
define('DB_UPDATE_VERSION', 1263);
|
||||
@@ -1270,7 +1270,7 @@ class App {
|
||||
'$js_strings' => js_strings(),
|
||||
'$zid' => get_my_address(),
|
||||
'$channel_id' => self::$profile['uid'] ?? 0,
|
||||
'$auto_save_draft' => ((isset(self::$profile['uid']) && feature_enabled(self::$profile['uid'], 'auto_save_draft')) ? "true" : "false"),
|
||||
'$auto_save_draft' => ((isset(self::$profile_uid) && feature_enabled(self::$profile_uid, 'auto_save_draft')) ? "true" : "false"),
|
||||
'$module' => App::$module,
|
||||
'$lang' => App::$language
|
||||
]
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
"pear/text_languagedetect": "^1.0",
|
||||
"commerceguys/intl": "~1.1.0",
|
||||
"lukasreschke/id3parser": "^0.0.3",
|
||||
"smarty/smarty": "^4.1",
|
||||
"smarty/smarty": "^5.4",
|
||||
"ramsey/uuid": "^4.1",
|
||||
"twbs/bootstrap": "^5.3",
|
||||
"blueimp/jquery-file-upload": "^10.3",
|
||||
@@ -56,8 +56,7 @@
|
||||
"stephenhill/base58": "^1.1",
|
||||
"mmccook/php-json-canonicalization-scheme": "^1.0",
|
||||
"scssphp/scssphp": "^1.12",
|
||||
"twbs/bootstrap-icons": "^1.11",
|
||||
"mikespub/php-epub-meta": "^2.3"
|
||||
"twbs/bootstrap-icons": "^1.11"
|
||||
},
|
||||
"require-dev": {
|
||||
"ext-yaml": "*",
|
||||
@@ -75,6 +74,11 @@
|
||||
"Zotlabs\\": "Zotlabs/"
|
||||
}
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
"Zotlabs\\Tests\\Unit\\": "tests/unit/"
|
||||
}
|
||||
},
|
||||
"minimum-stability": "stable",
|
||||
"config": {
|
||||
"notify-on-install": false,
|
||||
|
||||
1464
composer.lock
generated
1464
composer.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -1126,9 +1126,11 @@ function parseIdentityAwareHTML($Text) {
|
||||
if ($observer) {
|
||||
$s1 = '<span class="bb_observer" title="' . t('Different viewers will see this text differently') . '">';
|
||||
$s2 = '</span>';
|
||||
$obsBaseURL = $observer['xchan_connurl'];
|
||||
$obsBaseURL = preg_replace("/\/poco\/.*$/", '', $obsBaseURL);
|
||||
$Text = str_replace('[observer.baseurl]', $obsBaseURL, $Text);
|
||||
|
||||
$parsed = parse_url($observer['xchan_url']);
|
||||
$observer_base_url = unparse_url($parsed, ['scheme', 'host', 'port']);
|
||||
|
||||
$Text = str_replace('[observer.baseurl]', $observer_base_url, $Text);
|
||||
$Text = str_replace('[observer.url]',$observer['xchan_url'], $Text);
|
||||
$Text = str_replace('[observer.name]',$s1 . $observer['xchan_name'] . $s2, $Text);
|
||||
$Text = str_replace('[observer.address]',$s1 . $observer['xchan_addr'] . $s2, $Text);
|
||||
@@ -1311,9 +1313,11 @@ function bbcode($text, $options = []) {
|
||||
if ($observer) {
|
||||
$s1 = '<span class="bb_observer" title="' . t('Different viewers will see this text differently') . '">';
|
||||
$s2 = '</span>';
|
||||
$obsBaseURL = $observer['xchan_connurl'];
|
||||
$obsBaseURL = preg_replace("/\/poco\/.*$/", '', $obsBaseURL);
|
||||
$text = str_replace('[observer.baseurl]', $obsBaseURL, $text);
|
||||
|
||||
$parsed = parse_url($observer['xchan_url']);
|
||||
$observer_base_url = unparse_url($parsed, ['scheme', 'host', 'port']);
|
||||
|
||||
$text = str_replace('[observer.baseurl]', $observer_base_url, $text);
|
||||
$text = str_replace('[observer.url]',$observer['xchan_url'], $text);
|
||||
$text = str_replace('[observer.name]',$s1 . $observer['xchan_name'] . $s2, $text);
|
||||
$text = str_replace('[observer.address]',$s1 . $observer['xchan_addr'] . $s2, $text);
|
||||
|
||||
@@ -1255,6 +1255,7 @@ function hz_status_editor($x, $popup = false) {
|
||||
'$writefiles' => $writefiles,
|
||||
'$bold' => t('Bold'),
|
||||
'$italic' => t('Italic'),
|
||||
'$highlighter' => t('Highlight selected text'),
|
||||
'$underline' => t('Underline'),
|
||||
'$quote' => t('Quote'),
|
||||
'$code' => t('Code'),
|
||||
|
||||
@@ -10,6 +10,8 @@ class dba_pdo extends dba_driver {
|
||||
|
||||
public $driver_dbtype = null;
|
||||
|
||||
private string $server_version = '';
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @see dba_driver::connect()
|
||||
@@ -37,6 +39,7 @@ class dba_pdo extends dba_driver {
|
||||
try {
|
||||
$this->db = new PDO($dsn,$user,$pass);
|
||||
$this->db->setAttribute(PDO::ATTR_ERRMODE,PDO::ERRMODE_EXCEPTION);
|
||||
$this->server_version = $this->db->getAttribute(PDO::ATTR_SERVER_VERSION);
|
||||
}
|
||||
catch(PDOException $e) {
|
||||
if(file_exists('dbfail.out')) {
|
||||
@@ -73,9 +76,9 @@ class dba_pdo extends dba_driver {
|
||||
}
|
||||
}
|
||||
|
||||
$result = null;
|
||||
$result = false;
|
||||
$this->error = '';
|
||||
$select = ((stripos($sql, 'select') === 0) ? true : false);
|
||||
$select = stripos($sql, 'select') === 0 || stripos($sql, 'returning ') > 0;
|
||||
|
||||
try {
|
||||
$result = $this->db->query($sql, PDO::FETCH_ASSOC);
|
||||
@@ -115,6 +118,111 @@ class dba_pdo extends dba_driver {
|
||||
return (($this->error) ? false : $r);
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert a row into a table.
|
||||
*
|
||||
* The `$data` argument is an array of key/value pairs of the columns to
|
||||
* insert, where the key is the column name. Values are automatically
|
||||
* escaped if needed, and should be provided unescaped to this function.
|
||||
*
|
||||
* @note it is the callers responsibility to ensure that only valid
|
||||
* column names are passed as keys in the array.
|
||||
*
|
||||
* The inserted row will be returned.
|
||||
*
|
||||
* @param string $table The table to insert the row into.
|
||||
* @param array $data The data to insert as an array of column name => value pairs.
|
||||
* @param string $idcol The column name for the primary key of the table. We need to
|
||||
* specify this since we don't have a consistent naming of primary
|
||||
* id for tables.
|
||||
*
|
||||
* @return array|bool The complete record as read back from the database, or false if we
|
||||
* could not fetch it.
|
||||
*/
|
||||
public function insert(string $table, array $data, string $idcol): array|bool {
|
||||
$keys = array_keys($data);
|
||||
$values = array_map(
|
||||
fn ($v) => is_numeric($v) ? $v : "'" . dbesc($v) . "'",
|
||||
array_values($data)
|
||||
);
|
||||
|
||||
$query = "INSERT INTO {$table} ("
|
||||
. implode(', ', $keys) . ') VALUES ('
|
||||
. implode(', ', $values) . ')';
|
||||
|
||||
// MySQL is the only supported DB that don't support the returning
|
||||
// clause. Since the driver type is 'mysql' also for MariaDB, we need
|
||||
// to check the actual server version to be sure we only exclude actual
|
||||
// MySQL systems.
|
||||
if ($this->driver_dbtype !== 'mysql' || stripos($this->server_version, 'mariadb') !== false) {
|
||||
$query .= ' RETURNING *';
|
||||
}
|
||||
|
||||
$res = $this->q($query);
|
||||
|
||||
if (is_a($res, PDOStatement::class)) {
|
||||
//
|
||||
// Calling PDO::lastInsertId should be safe here.
|
||||
// The last inserted id is kept for each connection, so we're not risking
|
||||
// a race condition wrt inserts by other requests that happen simultaneously.
|
||||
//
|
||||
$id = $this->db->lastInsertId($table);
|
||||
|
||||
$res = $this->q("SELECT * FROM {$table} WHERE {$idcol} = {$id}");
|
||||
|
||||
if (is_a($res, PDOStatement::class)) {
|
||||
db_logger('dba_pdo: PDOStatement returned, did not expect that.');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (is_array($res)) {
|
||||
// Since we should never have more than one result, unwrap the array
|
||||
// so we only have the resulting row.
|
||||
$res = $res[0];
|
||||
}
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update an existing row in a table.
|
||||
*
|
||||
* The `$data` argument is an array of key/value pairs of the columns to
|
||||
* update, where the key is the column name. Values are automatically
|
||||
* escaped if needed, and should be provided unescaped to this function.
|
||||
*
|
||||
* @note it is the callers responsibility to ensure that only valid
|
||||
* column names are passed as keys in the array.
|
||||
*
|
||||
* The row to be updated is identified by `$idcol` and `$idval` as the
|
||||
* column name and value respectively. This should normally be the unique
|
||||
* id column of the table, but can in theory be any column with a unique
|
||||
* value that identifies a specific row.
|
||||
*
|
||||
* @param string $table The table to update.
|
||||
* @param array $data The columns to update as key => value pairs.
|
||||
* @param string $idcol The name of the id column to check $idval against.
|
||||
* @param mixed $idval The id of the row to update.
|
||||
*
|
||||
* @return bool True if the update succeeded, false otherwise.
|
||||
*/
|
||||
public function update(string $table, array $data, string $idcol, mixed $idval): bool {
|
||||
$set_statements = [];
|
||||
|
||||
foreach ($data as $k => $v) {
|
||||
$set_statements[] = "set {$k}=" . (is_numeric($v) ? $v : "'" . dbesc($v) . "'");
|
||||
}
|
||||
|
||||
$query = "UPDATE {$table} "
|
||||
. implode(', ', $set_statements)
|
||||
. " WHERE {$idcol} = {$idval}";
|
||||
|
||||
$res = $this->q($query);
|
||||
|
||||
return is_a($res, PDOStatement::class);
|
||||
}
|
||||
|
||||
function escape($str) {
|
||||
if($this->db && $this->connected) {
|
||||
return substr(substr(@$this->db->quote($str),1),0,-1);
|
||||
|
||||
@@ -102,7 +102,15 @@ function format_event_obj($jobject) {
|
||||
if (is_array($object) && (array_key_exists('summary', $object) || array_key_exists('name', $object))) {
|
||||
|
||||
$dtend = ((array_key_exists('endTime', $object)) ? $object['endTime'] : NULL_DATE);
|
||||
$title = ((isset($object['summary']) && $object['summary']) ? zidify_links(smilies(bbcode($object['summary']))) : $object['name']);
|
||||
|
||||
$title = $object['name'] ?? '';
|
||||
$content = html2bbcode($object['content']);
|
||||
|
||||
if (strpos($object['source']['content'], '[/event-description]') !== false) {
|
||||
$bbdescription = [];
|
||||
preg_match("/\[event\-description\](.*?)\[\/event\-description\]/ism", $object['source']['content'], $bbdescription);
|
||||
$content = $bbdescription[1];
|
||||
}
|
||||
|
||||
// mobilizon sets a timezone in the object
|
||||
// we will assume that events with an timezone should be adjusted
|
||||
@@ -146,15 +154,8 @@ function format_event_obj($jobject) {
|
||||
'$event_tz' => ['label' => t('Timezone'), 'value' => (($tz === date_default_timezone_get()) ? '' : $tz)]
|
||||
));
|
||||
|
||||
|
||||
$description = [];
|
||||
|
||||
if (strpos($object['source']['content'], '[/event-description]') !== false) {
|
||||
preg_match("/\[event\-description\](.*?)\[\/event\-description\]/ism", $object['source']['content'], $description);
|
||||
}
|
||||
|
||||
$event['content'] = replace_macros(get_markup_template('event_item_content.tpl'), array(
|
||||
'$description' => ((isset($description[1]))? zidify_links(smilies(bbcode($description[1]))) : EMPTY_STR),
|
||||
'$description' => zidify_links(smilies(bbcode($content, ['tryoembed' => false]))),
|
||||
'$location_label' => t('Location:'),
|
||||
'$location' => ((array_path_exists('location/name', $object)) ? zidify_links(smilies(bbcode($object['location']['name']))) : EMPTY_STR)
|
||||
));
|
||||
|
||||
@@ -228,15 +228,24 @@ function construct_activity_target($item) {
|
||||
if($item['target']) {
|
||||
$o = '<as:target>' . "\r\n";
|
||||
$r = json_decode($item['target'],false);
|
||||
if(! $r)
|
||||
|
||||
if (!$r) {
|
||||
return '';
|
||||
if($r->type)
|
||||
}
|
||||
|
||||
if (isset($r->type)) {
|
||||
$o .= '<as:obj_type>' . xmlify($r->type) . '</as:obj_type>' . "\r\n";
|
||||
if($r->id)
|
||||
}
|
||||
|
||||
if (isset($r->id)) {
|
||||
$o .= '<id>' . xmlify($r->id) . '</id>' . "\r\n";
|
||||
if($r->title)
|
||||
}
|
||||
|
||||
if (isset($r->title)) {
|
||||
$o .= '<title>' . xmlify($r->title) . '</title>' . "\r\n";
|
||||
if($r->links) {
|
||||
}
|
||||
|
||||
if (isset($r->link)) {
|
||||
/** @FIXME !!! */
|
||||
if(substr($r->link,0,1) === '<') {
|
||||
if(strstr($r->link,'&') && (! strstr($r->link,'&')))
|
||||
@@ -244,11 +253,14 @@ function construct_activity_target($item) {
|
||||
$r->link = preg_replace('/\<link(.*?)\"\>/','<link$1"/>',$r->link);
|
||||
$o .= $r->link;
|
||||
}
|
||||
else
|
||||
else {
|
||||
$o .= '<link rel="alternate" type="text/html" href="' . xmlify($r->link) . '" />' . "\r\n";
|
||||
}
|
||||
}
|
||||
if($r->content)
|
||||
|
||||
if(isset($r->content)) {
|
||||
$o .= '<content type="html" >' . xmlify(bbcode($r->content)) . '</content>' . "\r\n";
|
||||
}
|
||||
|
||||
$o .= '</as:target>' . "\r\n";
|
||||
|
||||
|
||||
@@ -3181,17 +3181,13 @@ function start_delivery_chain($channel, $item, $item_id, $parent, $group = false
|
||||
$item['parent_mid'] = $item['mid'];
|
||||
$item['thr_parent'] = $item['mid'];
|
||||
$item['llink'] = z_root() . '/display/' . $item['uuid'];
|
||||
$item['target'] = [
|
||||
'id' => str_replace('/item/', '/conversation/', $item['mid']),
|
||||
'type' => 'Collection',
|
||||
'attributedTo' => z_root() . '/channel/' . $channel['channel_address']
|
||||
];
|
||||
$item['tgt_type'] = 'Collection';
|
||||
}
|
||||
/*
|
||||
$r = q("UPDATE item SET author_xchan = '%s', mid = '%s', parent_mid = '%s', thr_parent = '%s', llink = '%s' WHERE id = %d",
|
||||
dbesc($item['author_xchan']),
|
||||
dbesc($item['mid']),
|
||||
dbesc($item['parent_mid']),
|
||||
dbesc($item['thr_parent']),
|
||||
dbesc($item['llink']),
|
||||
intval($item_id)
|
||||
);
|
||||
*/
|
||||
}
|
||||
|
||||
$private = (($channel['channel_allow_cid'] || $channel['channel_allow_gid']
|
||||
@@ -3237,7 +3233,7 @@ function start_delivery_chain($channel, $item, $item_id, $parent, $group = false
|
||||
|
||||
$r = q("update item set item_uplink = %d, item_nocomment = %d, item_flags = %d, owner_xchan = '%s', allow_cid = '%s', allow_gid = '%s',
|
||||
deny_cid = '%s', deny_gid = '%s', item_private = %d, public_policy = '%s', comment_policy = '%s', title = '%s', body = '%s', item_wall = %d, item_origin = %d,
|
||||
author_xchan = '%s', mid = '%s', parent_mid = '%s', thr_parent = '%s', llink = '%s' where id = %d",
|
||||
author_xchan = '%s', mid = '%s', parent_mid = '%s', thr_parent = '%s', llink = '%s', target = '%s', tgt_type = '%s' where id = %d",
|
||||
intval($item_uplink),
|
||||
intval($item_nocomment),
|
||||
intval($flag_bits),
|
||||
@@ -3258,6 +3254,8 @@ function start_delivery_chain($channel, $item, $item_id, $parent, $group = false
|
||||
dbesc($item['parent_mid']),
|
||||
dbesc($item['thr_parent']),
|
||||
dbesc($item['llink']),
|
||||
dbesc(json_encode($item['target'])),
|
||||
dbesc($item['tgt_type']),
|
||||
intval($item_id)
|
||||
);
|
||||
|
||||
@@ -3330,8 +3328,10 @@ function start_delivery_chain($channel, $item, $item_id, $parent, $group = false
|
||||
}
|
||||
else {
|
||||
// To prevent duplicates from possible clones of the forum/group,
|
||||
// will create a v5 UUID of the source item mid.
|
||||
$arr['uuid'] = uuid_from_url($item['mid']);
|
||||
// we will create a v5 UUID of the source item mid.
|
||||
// Add some extra entropy to prevent duplicate UUIDs with items where we already
|
||||
// created an UUID from the mid (activities which do not provide an UUID field).
|
||||
$arr['uuid'] = uuid_from_url($item['mid'] . '#group_item');
|
||||
$arr['mid'] = z_root() . '/item/' . $arr['uuid'];
|
||||
$arr['parent_mid'] = $arr['mid'];
|
||||
}
|
||||
@@ -5293,7 +5293,8 @@ function addToCollectionAndSync($ret) {
|
||||
}
|
||||
|
||||
xchan_query($items);
|
||||
$items = fetch_post_tags($items);
|
||||
// TODO: fetch_post_tags() will add term and iconfig twice if called twice and it looks like they are already added here
|
||||
// $items = fetch_post_tags($items);
|
||||
$sync_items = [];
|
||||
$sync_items[] = encode_item($items[0], true);
|
||||
|
||||
|
||||
@@ -2101,21 +2101,59 @@ function get_request_string($url) {
|
||||
|
||||
|
||||
/**
|
||||
* Builds a url from the result of `parse_url`.
|
||||
* Reconstructs a URL from its parsed components.
|
||||
*
|
||||
* @param array $parsed_url An associative array as produced by `parse_url`.
|
||||
* This function takes a parsed URL as an associative array and reconstructs
|
||||
* the URL based on the specified components (scheme, host, port, user, pass, path, query, fragment).
|
||||
* You can specify which components should be included in the final URL by passing the optional
|
||||
* `$parts` array. The function will return the complete URL string formed by combining
|
||||
* only the parts that exist in both the parsed URL and the `$parts` array.
|
||||
*
|
||||
* @return string The reassembled URL as a string.
|
||||
* @param array $parsed_url The parsed URL components as an associative array.
|
||||
* The array can include keys like 'scheme', 'host', 'port', 'user', 'pass',
|
||||
* 'path', 'query', 'fragment'.
|
||||
*
|
||||
* @param array $parts An optional array that specifies which components of the URL
|
||||
* should be included in the final string. Defaults to:
|
||||
* ['scheme', 'host', 'port', 'user', 'pass', 'path', 'query', 'fragment'].
|
||||
* If any of the components are not required, they can be omitted from the array.
|
||||
*
|
||||
* @return string The reconstructed URL as a string.
|
||||
*/
|
||||
function unparse_url(array $parsed_url): string {
|
||||
$scheme = isset($parsed_url['scheme']) ? $parsed_url['scheme'] . '://' : '';
|
||||
$host = isset($parsed_url['host']) ? $parsed_url['host'] : '';
|
||||
$port = isset($parsed_url['port']) ? ':' . $parsed_url['port'] : '';
|
||||
$user = isset($parsed_url['user']) ? $parsed_url['user'] : '';
|
||||
$pass = isset($parsed_url['pass']) ? ':' . $parsed_url['pass'] : '';
|
||||
$pass = ($user || $pass) ? "$pass@" : '';
|
||||
$path = isset($parsed_url['path']) ? $parsed_url['path'] : '';
|
||||
$query = isset($parsed_url['query']) ? '?' . $parsed_url['query'] : '';
|
||||
$fragment = isset($parsed_url['fragment']) ? '#' . $parsed_url['fragment'] : '';
|
||||
return $scheme . $user . $pass . $host . $port . $path . $query . $fragment;
|
||||
function unparse_url(array $parsed_url, array $parts = ['scheme', 'host', 'port', 'user', 'pass', 'path', 'query', 'fragment']): string {
|
||||
$url_parts = [];
|
||||
|
||||
if (in_array('scheme', $parts) && array_key_exists('scheme', $parsed_url)) {
|
||||
$url_parts[] = $parsed_url['scheme'] . '://';
|
||||
}
|
||||
|
||||
if (in_array('user', $parts) && array_key_exists('user', $parsed_url)) {
|
||||
$url_parts[] = $parsed_url['user'];
|
||||
if (in_array('pass', $parts) && array_key_exists('pass', $parsed_url)) {
|
||||
$url_parts[] = ':' . $parsed_url['pass'];
|
||||
}
|
||||
$url_parts[] = '@';
|
||||
}
|
||||
|
||||
if (in_array('host', $parts) && array_key_exists('host', $parsed_url)) {
|
||||
$url_parts[] = $parsed_url['host'];
|
||||
}
|
||||
|
||||
if (in_array('port', $parts) && array_key_exists('port', $parsed_url)) {
|
||||
$url_parts[] = ':' . $parsed_url['port'];
|
||||
}
|
||||
|
||||
if (in_array('path', $parts) && array_key_exists('path', $parsed_url)) {
|
||||
$url_parts[] = $parsed_url['path'];
|
||||
}
|
||||
|
||||
if (in_array('query', $parts) && array_key_exists('query', $parsed_url)) {
|
||||
$url_parts[] = '?' . $parsed_url['query'];
|
||||
}
|
||||
|
||||
if (in_array('fragment', $parts) && array_key_exists('fragment', $parsed_url)) {
|
||||
$url_parts[] = '#' . $parsed_url['fragment'];
|
||||
}
|
||||
|
||||
return implode('', $url_parts);
|
||||
}
|
||||
|
||||
@@ -143,6 +143,10 @@ function oembed_fetch_url($embedurl){
|
||||
|
||||
$furl = ((local_channel() && $zrl) ? zid($embedurl) : $embedurl);
|
||||
|
||||
if (empty($furl)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if($action !== 'block' && (! Config::Get('system','oembed_cache_disable'))) {
|
||||
$txt = Cache::get('[' . App::$videowidth . '] ' . $furl);
|
||||
}
|
||||
|
||||
@@ -2002,7 +2002,7 @@ function format_poll($item,$s,$opts) {
|
||||
$message .= t('Poll has ended');
|
||||
}
|
||||
else {
|
||||
$message .= sprintf(t('Poll ends in %s'), '<span class="autotime" title="' . $t . '"></span>');
|
||||
$message .= sprintf(t('Poll ends %s'), '<span class="autotime" title="' . $t . '"></span>');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3841,7 +3841,7 @@ function featured_sort($a,$b) {
|
||||
|
||||
|
||||
function unpunify($s) {
|
||||
if (function_exists('idn_to_utf8') && isset($s)) {
|
||||
if (function_exists('idn_to_utf8') && !empty($s)) {
|
||||
return idn_to_utf8($s);
|
||||
}
|
||||
return $s;
|
||||
@@ -3849,7 +3849,7 @@ function unpunify($s) {
|
||||
|
||||
|
||||
function punify($s) {
|
||||
if (function_exists('idn_to_ascii') && isset($s)) {
|
||||
if (function_exists('idn_to_ascii') && !empty($s)) {
|
||||
return idn_to_ascii($s);
|
||||
}
|
||||
return $s;
|
||||
|
||||
@@ -150,6 +150,9 @@ function clean_query_string($s = '') {
|
||||
*/
|
||||
|
||||
function drop_query_params($s, $p) {
|
||||
|
||||
$s = unescape_tags($s);
|
||||
|
||||
$parsed = parse_url($s);
|
||||
$query = '';
|
||||
$query_args = null;
|
||||
@@ -172,7 +175,7 @@ function drop_query_params($s, $p) {
|
||||
$parsed['query'] = $query;
|
||||
}
|
||||
|
||||
return unparse_url($parsed);
|
||||
return escape_tags(unparse_url($parsed));
|
||||
}
|
||||
|
||||
|
||||
|
||||
64
tests/unit/Module/OwaTest.php
Normal file
64
tests/unit/Module/OwaTest.php
Normal file
@@ -0,0 +1,64 @@
|
||||
<?php
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 Hubzilla Community
|
||||
* SPDX-FileContributor: Harald Eilertsen
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
namespace Zotlabs\Tests\Unit\Module;
|
||||
|
||||
class OwaTest extends TestCase
|
||||
{
|
||||
public function testShouldReturnErrorIfNoAuthorizationHeader(): void
|
||||
{
|
||||
// Expect the call to return error
|
||||
$this->expectJsonResponse([
|
||||
'success' => false,
|
||||
'message' => 'Missing or invalid authorization header.'
|
||||
]);
|
||||
|
||||
$this->get('owa');
|
||||
}
|
||||
|
||||
public function testShouldReturnErrorIfWrongAuthorizationHeader(): void
|
||||
{
|
||||
// Expect the call to return error
|
||||
$this->expectJsonResponse([
|
||||
'success' => false,
|
||||
'message' => 'Missing or invalid authorization header.'
|
||||
]);
|
||||
|
||||
$_SERVER['HTTP_AUTHORIZATION'] = 'Bearer kjkjhkjhkjh';
|
||||
$this->get('owa');
|
||||
}
|
||||
|
||||
public function testShouldReturnErrorIfInvalidAuthorizationHeader(): void
|
||||
{
|
||||
// Expect the call to return error
|
||||
$this->expectJsonResponse(['success' => false]);
|
||||
|
||||
$_SERVER['HTTP_AUTHORIZATION'] = 'Signature kjkjhkjhkjh';
|
||||
$this->get('owa');
|
||||
}
|
||||
|
||||
/**
|
||||
* Expect the request to be terminated and return a json response.
|
||||
*/
|
||||
private function expectJsonResponse(array $data): void
|
||||
{
|
||||
$this->getFunctionMock('Zotlabs\Module', 'json_return_and_die')
|
||||
->expects($this->once())
|
||||
->with(
|
||||
$this->identicalTo($data),
|
||||
$this->identicalTo('application/x-zot+json')
|
||||
)
|
||||
->willReturnCallback(
|
||||
function() {
|
||||
throw new KillmeException();
|
||||
}
|
||||
);
|
||||
|
||||
$this->expectException(KillmeException::class);
|
||||
}
|
||||
}
|
||||
@@ -8,14 +8,151 @@
|
||||
|
||||
namespace Zotlabs\Tests\Unit\Thumbs;
|
||||
|
||||
use PHPUnit\Framework\Attributes\{AfterClass, Before, BeforeClass};
|
||||
use Zotlabs\Thumbs\Epubthumb;
|
||||
use Zotlabs\Tests\Unit\UnitTestCase;
|
||||
|
||||
class EpubthumbTest extends UnitTestCase {
|
||||
function testEpubThumbMatch(): void {
|
||||
$thumbnailer = new Epubthumb();
|
||||
use ZipArchive;
|
||||
|
||||
$this->assertTrue($thumbnailer->Match('application/epub+zip'));
|
||||
$this->assertFalse($thumbnailer->Match('application/zip'));
|
||||
class EpubthumbTest extends UnitTestCase {
|
||||
private const TMPDIR = __DIR__ . '/tmp';
|
||||
|
||||
private Epubthumb $thumbnailer;
|
||||
|
||||
/**
|
||||
* Create a temp dir to use for the tests in this class.
|
||||
*/
|
||||
#[BeforeClass]
|
||||
static function setupTmpDir(): void {
|
||||
if (!is_dir(self::TMPDIR)) {
|
||||
mkdir(self::TMPDIR);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean up and remove the temp dir after the tests.
|
||||
*/
|
||||
#[AfterClass]
|
||||
static function cleanupTmpDir(): void {
|
||||
$files = scandir(self::TMPDIR);
|
||||
if ($files !== false) {
|
||||
foreach($files as $f) {
|
||||
if ($f[0] !== '.') {
|
||||
unlink(self::TMPDIR . '/' . $f);
|
||||
}
|
||||
}
|
||||
}
|
||||
rmdir(self::TMPDIR);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the thumbnailer object for tests.
|
||||
*
|
||||
* This is run before each test, so that each test has it's own
|
||||
* instance of the thumbnailer.
|
||||
*/
|
||||
#[Before]
|
||||
function createThumbnailer(): void {
|
||||
$this->thumbnailer = new Epubthumb();
|
||||
}
|
||||
|
||||
/*
|
||||
* Tests
|
||||
*/
|
||||
|
||||
public function testEpubThumbMatch(): void {
|
||||
$this->assertTrue($this->thumbnailer->Match('application/epub+zip'));
|
||||
$this->assertFalse($this->thumbnailer->Match('application/zip'));
|
||||
}
|
||||
|
||||
public function testNoThumbnailCreatedForFileThatDontExist(): void {
|
||||
$this->checkCreateThumbnail(self::TMPDIR . '/nonexisting.epub', false);
|
||||
}
|
||||
|
||||
public function testNoThumbnailCreatedIfNotAZipArchive(): void {
|
||||
$filename = self::TMPDIR . '/notazip.epub';
|
||||
|
||||
file_put_contents($filename, 'This is not a ZIP file!');
|
||||
|
||||
$this->checkCreateThumbnail($filename, false);
|
||||
}
|
||||
|
||||
public function testNoThumbnailCreatedIfInvalidEpub(): void {
|
||||
$filename = self::TMPDIR . '/nocontainer.epub';
|
||||
|
||||
$epub = new ZipArchive();
|
||||
$epub->open($filename, ZipArchive::CREATE);
|
||||
$epub->addFromString('somefile.txt', 'It was a dark an stormy night...');
|
||||
$epub->close();
|
||||
|
||||
$this->checkCreateThumbnail($filename, false);
|
||||
}
|
||||
|
||||
public function testNoThumbnailCreatedIfCoverFileMissing(): void {
|
||||
$filename = self::TMPDIR . '/good.epub';
|
||||
|
||||
$epub = new ZipArchive();
|
||||
$epub->open($filename, ZipArchive::CREATE);
|
||||
$this->addEpubContainer($epub);
|
||||
$this->addEpubPackage($epub);
|
||||
$epub->close();
|
||||
|
||||
$this->checkCreateThumbnail($filename, false);
|
||||
}
|
||||
|
||||
public function testCreateCoverFromEpub(): void {
|
||||
$filename = self::TMPDIR . '/good.epub';
|
||||
|
||||
$epub = new ZipArchive();
|
||||
$epub->open($filename, ZipArchive::CREATE);
|
||||
$this->addEpubContainer($epub);
|
||||
$this->addEpubPackage($epub);
|
||||
$epub->addFile(PROJECT_BASE . '/images/red-koala.png', 'EPUB/cover.png');
|
||||
$epub->close();
|
||||
|
||||
$this->checkCreateThumbnail($filename, true);
|
||||
}
|
||||
|
||||
/*
|
||||
* Helper functions
|
||||
*/
|
||||
|
||||
private function checkCreateThumbnail(string $filename, bool $expectThumbnail): void {
|
||||
$attach = [ 'content' => $filename ];
|
||||
$this->thumbnailer->Thumb($attach, 0);
|
||||
|
||||
$this->assertEquals($expectThumbnail, file_exists($filename . '.thumb'));
|
||||
}
|
||||
|
||||
private function addEpubContainer(ZipArchive $epub): void {
|
||||
$xml = <<<XML
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<container version="1.0" xmlns="urn:oasis:names:tc:opendocument:xmlns:container">
|
||||
<rootfiles>
|
||||
<rootfile full-path="EPUB/package.opf" media-type="application/oebps-package+xml"/>
|
||||
</rootfiles>
|
||||
</container>
|
||||
XML;
|
||||
|
||||
$epub->addEmptyDir('META-INF');
|
||||
$epub->addFromString('META-INF/container.xml', $xml);
|
||||
}
|
||||
|
||||
private function addEpubPackage(ZipArchive $epub): void {
|
||||
$xml = <<<XML
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<package xmlns="http://www.idpf.org/2007/opf" version="3.0" unique-identifier="pub-identifier">
|
||||
<manifest>
|
||||
<item
|
||||
properties="cover-image"
|
||||
id="ci"
|
||||
href="cover.png"
|
||||
media-type="image/png" />
|
||||
</manifest>
|
||||
</package>
|
||||
XML;
|
||||
|
||||
$epub->addEmptyDir('EPUB');
|
||||
$epub->addFromString('EPUB/package.opf', $xml);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,4 +67,56 @@ class NetworkTest extends Zotlabs\Tests\Unit\UnitTestCase {
|
||||
['address-tag@example.com', true],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the unparse_url function.
|
||||
*
|
||||
*/
|
||||
public function test_unparse_url_full()
|
||||
{
|
||||
$parsed_url = [
|
||||
'scheme' => 'https',
|
||||
'host' => 'www.example.com',
|
||||
'port' => '8080',
|
||||
'user' => 'username',
|
||||
'pass' => 'password',
|
||||
'path' => '/path',
|
||||
'query' => 'param=value',
|
||||
'fragment' => 'section'
|
||||
];
|
||||
|
||||
$expected = 'https://username:password@www.example.com:8080/path?param=value#section';
|
||||
$this->assertEquals($expected, unparse_url($parsed_url));
|
||||
}
|
||||
|
||||
public function test_unparse_url_partial()
|
||||
{
|
||||
$parsed_url = [
|
||||
'scheme' => 'http',
|
||||
'host' => 'example.com',
|
||||
'path' => '/index.php'
|
||||
];
|
||||
|
||||
$expected = 'http://example.com/index.php';
|
||||
$this->assertEquals($expected, unparse_url($parsed_url));
|
||||
}
|
||||
|
||||
public function test_unparse_url_custom()
|
||||
{
|
||||
$parsed_url = [
|
||||
'scheme' => 'https',
|
||||
'host' => 'www.example.com',
|
||||
'port' => '443',
|
||||
'path' => '/api'
|
||||
];
|
||||
|
||||
$parts = ['scheme', 'host'];
|
||||
$expected = 'https://www.example.com';
|
||||
$this->assertEquals($expected, unparse_url($parsed_url, $parts));
|
||||
}
|
||||
|
||||
public function test_unparse_url_empty()
|
||||
{
|
||||
$this->assertEquals('', unparse_url([]));
|
||||
}
|
||||
}
|
||||
|
||||
140
tests/unit/includes/dba/DbaPdoTest.php
Normal file
140
tests/unit/includes/dba/DbaPdoTest.php
Normal file
@@ -0,0 +1,140 @@
|
||||
<?php
|
||||
/**
|
||||
* Tests for `includes/dba_pdo.php`.
|
||||
*
|
||||
* SPDX-FileCopyrightText: 2024 Hubzilla Community
|
||||
* SPDX-FileContributor: Harald Eilertsen
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
namespace Zotlabs\Tests\Unit\includes;
|
||||
|
||||
use DBA;
|
||||
use PDO;
|
||||
use PDOStatement;
|
||||
use PHPUnit\Framework\Attributes\DataProvider;
|
||||
use Zotlabs\Tests\Unit\UnitTestCase;
|
||||
|
||||
class DbaPdoTest extends UnitTestCase
|
||||
{
|
||||
public function testInsertingRowWithRturningClauseReturnsInsertedRow(): void
|
||||
{
|
||||
// MySQL does not support the `returning` clause, so we skip the test
|
||||
// for that DB backend.
|
||||
$this->skipIfMySQL();
|
||||
|
||||
// Let's manually insert a row in the config table.
|
||||
// This is just because it's a conventient table to test
|
||||
// against
|
||||
$res = q(<<<SQL
|
||||
INSERT INTO config (cat, k, v)
|
||||
VALUES ('test', 'a key', 'A value')
|
||||
RETURNING *
|
||||
SQL);
|
||||
|
||||
$this->assertIsArray($res);
|
||||
$this->assertIsArray($res[0]);
|
||||
$this->assertTrue($res[0]['id'] > 0);
|
||||
$this->assertEquals('test', $res[0]['cat']);
|
||||
$this->assertEquals('a key', $res[0]['k']);
|
||||
$this->assertEquals('A value', $res[0]['v']);
|
||||
}
|
||||
|
||||
#[DataProvider('insertRowProvider')]
|
||||
public function testInsertRow(string $table, array $data, string $id): void
|
||||
{
|
||||
$res = DBA::$dba->insert($table, $data, $id);
|
||||
|
||||
$this->assertIsArray($res);
|
||||
|
||||
// Make sure the result contains the expected id
|
||||
$this->assertArrayHasKey($id, $res);
|
||||
|
||||
foreach ($data as $key => $value) {
|
||||
$this->assertEquals($value, $res[$key]);
|
||||
}
|
||||
}
|
||||
|
||||
#[DataProvider('insertRowProvider')]
|
||||
public function testInsertShouldReturnFalseIfInsertFails(
|
||||
string $table,
|
||||
array $data,
|
||||
string $id
|
||||
): void
|
||||
{
|
||||
$res1 = DBA::$dba->insert($table, $data, $id);
|
||||
$this->assertIsArray($res1);
|
||||
|
||||
// Inserting the same row again should fail.
|
||||
$res2 = DBA::$dba->insert($table, $data, $id);
|
||||
$this->assertFalse($res2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Dataprovider for testInertRow.
|
||||
*
|
||||
* @return array An array of [ $table, $data, $id ] elements.
|
||||
*/
|
||||
public static function insertRowProvider(): array
|
||||
{
|
||||
return [
|
||||
'table with numeric primary id' => [
|
||||
'config',
|
||||
[ 'cat' => 'test', 'k' => 'a key', 'v' => 'A value' ],
|
||||
'id',
|
||||
],
|
||||
'table with text primary id' => [
|
||||
'cache',
|
||||
[ 'k' => 'some key', 'v' => 'cached value', 'updated' => date('Y-m-d H:i:s')],
|
||||
'k',
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
public function testUpdateRow(): void
|
||||
{
|
||||
// Let's fetch a row from the config table
|
||||
$res = q("SELECT * FROM config WHERE cat = 'system' AND k = 'baseurl'");
|
||||
|
||||
$this->assertIsArray($res);
|
||||
$this->assertIsArray($res[0]);
|
||||
|
||||
$row = $res[0];
|
||||
|
||||
// Update the baseurl
|
||||
$updated = DBA::$dba->update(
|
||||
'config',
|
||||
[ 'v' => 'https://some.other_site.test/' ],
|
||||
'id',
|
||||
$row['id']
|
||||
);
|
||||
|
||||
$this->assertTrue($updated);
|
||||
|
||||
// Verify that the record was updated
|
||||
$updated_res = q("SELECT * FROM config WHERE cat = 'system' AND k = 'baseurl'");
|
||||
$this->assertIsArray($updated_res);
|
||||
|
||||
$updated_row = $updated_res[0];
|
||||
|
||||
$this->assertIsArray($updated_row);
|
||||
$this->assertEquals($row['id'], $updated_row['id']);
|
||||
$this->assertEquals('system', $updated_row['cat']);
|
||||
$this->assertEquals('baseurl', $updated_row['k']);
|
||||
$this->assertEquals('https://some.other_site.test/', $updated_row['v']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark the test as skipped if the current db is MySQL.
|
||||
*/
|
||||
private function skipIfMySQL(): void {
|
||||
$driver = DBA::$dba->db->getAttribute(PDO::ATTR_DRIVER_NAME);
|
||||
$version = DBA::$dba->db->getAttribute(PDO::ATTR_SERVER_VERSION);
|
||||
|
||||
if ($driver === 'mysql' && stripos($version, 'mariadb') === false) {
|
||||
$this->markTestSkipped("RETURNING clause not supported for {$driver}");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -6,9 +6,9 @@
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: 10.0RC\n"
|
||||
"Project-Id-Version: 10.2RC\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2024-12-13 08:47+0000\n"
|
||||
"POT-Creation-Date: 2025-03-05 10:11+0000\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
@@ -43,7 +43,7 @@ msgstr ""
|
||||
#: ../../addon/redphotos/redphotos.php:136
|
||||
#: ../../addon/pageheader/Mod_Pageheader.php:52
|
||||
#: ../../addon/ijpost/Mod_Ijpost.php:72 ../../addon/redred/Mod_Redred.php:88
|
||||
#: ../../addon/startpage/Mod_Startpage.php:71
|
||||
#: ../../addon/startpage/Mod_Startpage.php:75
|
||||
#: ../../addon/libertree/Mod_Libertree.php:68 ../../addon/logrot/logrot.php:35
|
||||
#: ../../addon/pubcrawl/Mod_Pubcrawl.php:61
|
||||
#: ../../addon/dwpost/Mod_Dwpost.php:78 ../../addon/diaspora/diaspora.php:90
|
||||
@@ -183,7 +183,7 @@ msgstr ""
|
||||
#: ../../view/theme/redbasic/php/config.php:202
|
||||
#: ../../view/theme/redbasic/php/config.php:203
|
||||
#: ../../view/theme/redbasic/php/config.php:215
|
||||
#: ../../include/conversation.php:1273
|
||||
#: ../../include/conversation.php:1274
|
||||
#: ../../addon/socialauth/Mod_SocialAuth.php:218
|
||||
#: ../../addon/ijpost/Mod_Ijpost.php:61 ../../addon/redred/Mod_Redred.php:61
|
||||
#: ../../addon/libertree/Mod_Libertree.php:57
|
||||
@@ -263,7 +263,7 @@ msgstr ""
|
||||
#: ../../view/theme/redbasic/php/config.php:202
|
||||
#: ../../view/theme/redbasic/php/config.php:203
|
||||
#: ../../view/theme/redbasic/php/config.php:215
|
||||
#: ../../include/conversation.php:1273
|
||||
#: ../../include/conversation.php:1274
|
||||
#: ../../addon/socialauth/Mod_SocialAuth.php:218
|
||||
#: ../../addon/ijpost/Mod_Ijpost.php:61 ../../addon/redred/Mod_Redred.php:61
|
||||
#: ../../addon/libertree/Mod_Libertree.php:57
|
||||
@@ -444,27 +444,27 @@ msgstr ""
|
||||
msgid "Login failed."
|
||||
msgstr ""
|
||||
|
||||
#: ../../include/oembed.php:155
|
||||
#: ../../include/oembed.php:159
|
||||
msgid "View PDF"
|
||||
msgstr ""
|
||||
|
||||
#: ../../include/oembed.php:390
|
||||
#: ../../include/oembed.php:394
|
||||
msgid " by "
|
||||
msgstr ""
|
||||
|
||||
#: ../../include/oembed.php:391
|
||||
#: ../../include/oembed.php:395
|
||||
msgid " on "
|
||||
msgstr ""
|
||||
|
||||
#: ../../include/oembed.php:424
|
||||
#: ../../include/oembed.php:428
|
||||
msgid "Embedded content"
|
||||
msgstr ""
|
||||
|
||||
#: ../../include/oembed.php:433
|
||||
#: ../../include/oembed.php:437
|
||||
msgid "Embedding disabled"
|
||||
msgstr ""
|
||||
|
||||
#: ../../include/event.php:35 ../../include/event.php:133
|
||||
#: ../../include/event.php:35 ../../include/event.php:141
|
||||
msgid "l F d, Y \\@ g:i A"
|
||||
msgstr ""
|
||||
|
||||
@@ -476,91 +476,91 @@ msgstr ""
|
||||
msgid "Finishes:"
|
||||
msgstr ""
|
||||
|
||||
#: ../../include/event.php:67 ../../include/event.php:158
|
||||
#: ../../include/event.php:67 ../../include/event.php:159
|
||||
#: ../../include/channel.php:1642 ../../Zotlabs/Module/Directory.php:354
|
||||
msgid "Location:"
|
||||
msgstr ""
|
||||
|
||||
#: ../../include/event.php:133
|
||||
#: ../../include/event.php:141
|
||||
msgid "l F d, Y"
|
||||
msgstr ""
|
||||
|
||||
#: ../../include/event.php:137
|
||||
#: ../../include/event.php:145
|
||||
msgid "Start:"
|
||||
msgstr ""
|
||||
|
||||
#: ../../include/event.php:141
|
||||
#: ../../include/event.php:149
|
||||
msgid "End:"
|
||||
msgstr ""
|
||||
|
||||
#: ../../include/event.php:146 ../../addon/openid/MysqlProvider.php:67
|
||||
#: ../../include/event.php:154 ../../addon/openid/MysqlProvider.php:67
|
||||
msgid "Timezone"
|
||||
msgstr ""
|
||||
|
||||
#: ../../include/event.php:1245
|
||||
#: ../../include/event.php:1246
|
||||
msgid "This event has been added to your calendar."
|
||||
msgstr ""
|
||||
|
||||
#: ../../include/event.php:1365 ../../include/conversation.php:153
|
||||
#: ../../include/event.php:1366 ../../include/conversation.php:153
|
||||
#: ../../include/text.php:2359 ../../Zotlabs/Module/Tagger.php:77
|
||||
#: ../../Zotlabs/Module/Like.php:453
|
||||
#: ../../Zotlabs/Module/Channel_calendar.php:209
|
||||
msgid "event"
|
||||
msgstr ""
|
||||
|
||||
#: ../../include/event.php:1449
|
||||
#: ../../include/event.php:1450
|
||||
msgid "Not specified"
|
||||
msgstr ""
|
||||
|
||||
#: ../../include/event.php:1450
|
||||
#: ../../include/event.php:1451
|
||||
msgid "Needs Action"
|
||||
msgstr ""
|
||||
|
||||
#: ../../include/event.php:1451
|
||||
#: ../../include/event.php:1452
|
||||
msgid "Completed"
|
||||
msgstr ""
|
||||
|
||||
#: ../../include/event.php:1452
|
||||
#: ../../include/event.php:1453
|
||||
msgid "In Process"
|
||||
msgstr ""
|
||||
|
||||
#: ../../include/event.php:1453
|
||||
#: ../../include/event.php:1454
|
||||
msgid "Cancelled"
|
||||
msgstr ""
|
||||
|
||||
#: ../../include/event.php:1534 ../../include/connections.php:790
|
||||
#: ../../include/event.php:1535 ../../include/connections.php:790
|
||||
#: ../../Zotlabs/Module/Connedit.php:741 ../../Zotlabs/Module/Cdav.php:1377
|
||||
msgid "Mobile"
|
||||
msgstr ""
|
||||
|
||||
#: ../../include/event.php:1535 ../../include/connections.php:791
|
||||
#: ../../include/event.php:1536 ../../include/connections.php:791
|
||||
#: ../../Zotlabs/Widget/Notifications.php:43
|
||||
#: ../../Zotlabs/Module/Connedit.php:742 ../../Zotlabs/Module/Cdav.php:1378
|
||||
msgid "Home"
|
||||
msgstr ""
|
||||
|
||||
#: ../../include/event.php:1536 ../../include/connections.php:792
|
||||
#: ../../include/event.php:1537 ../../include/connections.php:792
|
||||
msgid "Home, Voice"
|
||||
msgstr ""
|
||||
|
||||
#: ../../include/event.php:1537 ../../include/connections.php:793
|
||||
#: ../../include/event.php:1538 ../../include/connections.php:793
|
||||
msgid "Home, Fax"
|
||||
msgstr ""
|
||||
|
||||
#: ../../include/event.php:1538 ../../include/connections.php:794
|
||||
#: ../../include/event.php:1539 ../../include/connections.php:794
|
||||
#: ../../Zotlabs/Module/Connedit.php:743 ../../Zotlabs/Module/Cdav.php:1379
|
||||
msgid "Work"
|
||||
msgstr ""
|
||||
|
||||
#: ../../include/event.php:1539 ../../include/connections.php:795
|
||||
#: ../../include/event.php:1540 ../../include/connections.php:795
|
||||
msgid "Work, Voice"
|
||||
msgstr ""
|
||||
|
||||
#: ../../include/event.php:1540 ../../include/connections.php:796
|
||||
#: ../../include/event.php:1541 ../../include/connections.php:796
|
||||
msgid "Work, Fax"
|
||||
msgstr ""
|
||||
|
||||
#: ../../include/event.php:1541 ../../include/event.php:1548
|
||||
#: ../../include/event.php:1542 ../../include/event.php:1549
|
||||
#: ../../include/selectors.php:64 ../../include/selectors.php:81
|
||||
#: ../../include/selectors.php:119 ../../include/selectors.php:155
|
||||
#: ../../include/connections.php:797 ../../include/connections.php:804
|
||||
@@ -569,7 +569,7 @@ msgstr ""
|
||||
msgid "Other"
|
||||
msgstr ""
|
||||
|
||||
#: ../../include/feedutils.php:851 ../../include/text.php:1580
|
||||
#: ../../include/feedutils.php:863 ../../include/text.php:1580
|
||||
msgid "unknown"
|
||||
msgstr ""
|
||||
|
||||
@@ -617,7 +617,7 @@ msgstr ""
|
||||
msgid "Visible to specific connections."
|
||||
msgstr ""
|
||||
|
||||
#: ../../include/items.php:3491 ../../Zotlabs/Lib/Activity.php:2280
|
||||
#: ../../include/items.php:3491 ../../Zotlabs/Lib/Activity.php:2282
|
||||
#: ../../Zotlabs/Module/Share.php:124
|
||||
#, php-format
|
||||
msgid "🔁 Repeated %1$s's %2$s"
|
||||
@@ -1530,7 +1530,7 @@ msgstr ""
|
||||
#: ../../include/cdav.php:158 ../../include/cdav.php:159
|
||||
#: ../../include/cdav.php:167 ../../include/conversation.php:1006
|
||||
#: ../../Zotlabs/Lib/Apps.php:1168 ../../Zotlabs/Lib/Apps.php:1252
|
||||
#: ../../Zotlabs/Lib/Activity.php:1724 ../../Zotlabs/Widget/Album.php:90
|
||||
#: ../../Zotlabs/Lib/Activity.php:1726 ../../Zotlabs/Widget/Album.php:90
|
||||
#: ../../Zotlabs/Widget/Pinned.php:256 ../../Zotlabs/Widget/Portfolio.php:99
|
||||
#: ../../Zotlabs/Module/Embedphotos.php:177 ../../Zotlabs/Module/Photos.php:788
|
||||
#: ../../Zotlabs/Module/Photos.php:1246
|
||||
@@ -1635,7 +1635,7 @@ msgstr ""
|
||||
msgid "dislikes"
|
||||
msgstr ""
|
||||
|
||||
#: ../../include/taxonomy.php:677 ../../include/conversation.php:1560
|
||||
#: ../../include/taxonomy.php:677 ../../include/conversation.php:1561
|
||||
#: ../../Zotlabs/Module/Photos.php:1129
|
||||
msgctxt "noun"
|
||||
msgid "Like"
|
||||
@@ -2125,7 +2125,7 @@ msgstr ""
|
||||
msgid "Required"
|
||||
msgstr ""
|
||||
|
||||
#: ../../include/zid.php:417
|
||||
#: ../../include/zid.php:420
|
||||
#, php-format
|
||||
msgid "OpenWebAuth: %1$s welcomes %2$s"
|
||||
msgstr ""
|
||||
@@ -2492,7 +2492,7 @@ msgid "Confirm delete"
|
||||
msgstr ""
|
||||
|
||||
#: ../../include/conversation.php:1209 ../../addon/hsse/hsse.php:153
|
||||
#: ../../Zotlabs/Lib/ThreadItem.php:809 ../../Zotlabs/Module/Webpages.php:256
|
||||
#: ../../Zotlabs/Lib/ThreadItem.php:810 ../../Zotlabs/Module/Webpages.php:256
|
||||
#: ../../Zotlabs/Module/Photos.php:1096
|
||||
msgid "Preview"
|
||||
msgstr ""
|
||||
@@ -2523,32 +2523,36 @@ msgstr ""
|
||||
msgid "Italic"
|
||||
msgstr ""
|
||||
|
||||
#: ../../include/conversation.php:1258 ../../addon/hsse/hsse.php:202
|
||||
#: ../../Zotlabs/Lib/ThreadItem.php:802
|
||||
#: ../../include/conversation.php:1258 ../../Zotlabs/Lib/ThreadItem.php:802
|
||||
msgid "Highlight selected text"
|
||||
msgstr ""
|
||||
|
||||
#: ../../include/conversation.php:1259 ../../addon/hsse/hsse.php:202
|
||||
#: ../../Zotlabs/Lib/ThreadItem.php:803
|
||||
msgid "Underline"
|
||||
msgstr ""
|
||||
|
||||
#: ../../include/conversation.php:1259 ../../addon/hsse/hsse.php:203
|
||||
#: ../../Zotlabs/Lib/ThreadItem.php:803
|
||||
#: ../../include/conversation.php:1260 ../../addon/hsse/hsse.php:203
|
||||
#: ../../Zotlabs/Lib/ThreadItem.php:804
|
||||
msgid "Quote"
|
||||
msgstr ""
|
||||
|
||||
#: ../../include/conversation.php:1260 ../../addon/hsse/hsse.php:204
|
||||
#: ../../Zotlabs/Lib/ThreadItem.php:804
|
||||
#: ../../include/conversation.php:1261 ../../addon/hsse/hsse.php:204
|
||||
#: ../../Zotlabs/Lib/ThreadItem.php:805
|
||||
msgid "Code"
|
||||
msgstr ""
|
||||
|
||||
#: ../../include/conversation.php:1261 ../../addon/hsse/hsse.php:205
|
||||
#: ../../Zotlabs/Lib/ThreadItem.php:806
|
||||
#: ../../include/conversation.php:1262 ../../addon/hsse/hsse.php:205
|
||||
#: ../../Zotlabs/Lib/ThreadItem.php:807
|
||||
msgid "Attach/Upload file"
|
||||
msgstr ""
|
||||
|
||||
#: ../../include/conversation.php:1264 ../../addon/wiki/Mod_Wiki.php:397
|
||||
#: ../../include/conversation.php:1265 ../../addon/wiki/Mod_Wiki.php:397
|
||||
#: ../../addon/hsse/hsse.php:208
|
||||
msgid "Embed an image from your albums"
|
||||
msgstr ""
|
||||
|
||||
#: ../../include/conversation.php:1265 ../../include/conversation.php:1320
|
||||
#: ../../include/conversation.php:1266 ../../include/conversation.php:1321
|
||||
#: ../../addon/cards/Mod_Card_edit.php:126
|
||||
#: ../../addon/articles/Mod_Article_edit.php:126
|
||||
#: ../../addon/wiki/Mod_Wiki.php:365 ../../addon/wiki/Mod_Wiki.php:398
|
||||
@@ -2567,118 +2571,118 @@ msgstr ""
|
||||
msgid "Cancel"
|
||||
msgstr ""
|
||||
|
||||
#: ../../include/conversation.php:1266 ../../include/conversation.php:1319
|
||||
#: ../../include/conversation.php:1267 ../../include/conversation.php:1320
|
||||
#: ../../addon/wiki/Mod_Wiki.php:399 ../../addon/hsse/hsse.php:210
|
||||
#: ../../addon/hsse/hsse.php:257 ../../Zotlabs/Module/Cover_photo.php:387
|
||||
#: ../../Zotlabs/Module/Profile_photo.php:554
|
||||
msgid "OK"
|
||||
msgstr ""
|
||||
|
||||
#: ../../include/conversation.php:1268 ../../addon/hsse/hsse.php:212
|
||||
#: ../../include/conversation.php:1269 ../../addon/hsse/hsse.php:212
|
||||
msgid "Toggle voting"
|
||||
msgstr ""
|
||||
|
||||
#: ../../include/conversation.php:1269
|
||||
#: ../../include/conversation.php:1270
|
||||
msgid "Toggle poll"
|
||||
msgstr ""
|
||||
|
||||
#: ../../include/conversation.php:1270
|
||||
#: ../../include/conversation.php:1271
|
||||
msgid "Option"
|
||||
msgstr ""
|
||||
|
||||
#: ../../include/conversation.php:1271
|
||||
#: ../../include/conversation.php:1272
|
||||
msgid "Add option"
|
||||
msgstr ""
|
||||
|
||||
#: ../../include/conversation.php:1272
|
||||
#: ../../include/conversation.php:1273
|
||||
msgid "Minutes"
|
||||
msgstr ""
|
||||
|
||||
#: ../../include/conversation.php:1272
|
||||
#: ../../include/conversation.php:1273
|
||||
msgid "Hours"
|
||||
msgstr ""
|
||||
|
||||
#: ../../include/conversation.php:1272
|
||||
#: ../../include/conversation.php:1273
|
||||
msgid "Days"
|
||||
msgstr ""
|
||||
|
||||
#: ../../include/conversation.php:1273
|
||||
#: ../../include/conversation.php:1274
|
||||
msgid "Allow multiple answers"
|
||||
msgstr ""
|
||||
|
||||
#: ../../include/conversation.php:1275 ../../addon/hsse/hsse.php:215
|
||||
#: ../../include/conversation.php:1276 ../../addon/hsse/hsse.php:215
|
||||
msgid "Disable comments"
|
||||
msgstr ""
|
||||
|
||||
#: ../../include/conversation.php:1276 ../../addon/hsse/hsse.php:216
|
||||
#: ../../include/conversation.php:1277 ../../addon/hsse/hsse.php:216
|
||||
msgid "Toggle comments"
|
||||
msgstr ""
|
||||
|
||||
#: ../../include/conversation.php:1282 ../../addon/cards/Mod_Card_edit.php:111
|
||||
#: ../../include/conversation.php:1283 ../../addon/cards/Mod_Card_edit.php:111
|
||||
#: ../../addon/articles/Mod_Article_edit.php:111 ../../addon/hsse/hsse.php:221
|
||||
#: ../../Zotlabs/Module/Photos.php:667 ../../Zotlabs/Module/Photos.php:1042
|
||||
#: ../../Zotlabs/Module/Editblock.php:129
|
||||
msgid "Title (optional)"
|
||||
msgstr ""
|
||||
|
||||
#: ../../include/conversation.php:1283
|
||||
#: ../../include/conversation.php:1284
|
||||
msgid "Summary (optional)"
|
||||
msgstr ""
|
||||
|
||||
#: ../../include/conversation.php:1286 ../../addon/hsse/hsse.php:224
|
||||
#: ../../include/conversation.php:1287 ../../addon/hsse/hsse.php:224
|
||||
msgid "Categories (optional, comma-separated list)"
|
||||
msgstr ""
|
||||
|
||||
#: ../../include/conversation.php:1287 ../../addon/hsse/hsse.php:225
|
||||
#: ../../include/conversation.php:1288 ../../addon/hsse/hsse.php:225
|
||||
msgid "Permission settings"
|
||||
msgstr ""
|
||||
|
||||
#: ../../include/conversation.php:1309 ../../addon/hsse/hsse.php:247
|
||||
#: ../../include/conversation.php:1310 ../../addon/hsse/hsse.php:247
|
||||
msgid "Other networks and post services"
|
||||
msgstr ""
|
||||
|
||||
#: ../../include/conversation.php:1312 ../../addon/hsse/hsse.php:250
|
||||
#: ../../include/conversation.php:1313 ../../addon/hsse/hsse.php:250
|
||||
msgid "Set expiration date"
|
||||
msgstr ""
|
||||
|
||||
#: ../../include/conversation.php:1315 ../../addon/hsse/hsse.php:253
|
||||
#: ../../include/conversation.php:1316 ../../addon/hsse/hsse.php:253
|
||||
msgid "Set publish date"
|
||||
msgstr ""
|
||||
|
||||
#: ../../include/conversation.php:1317 ../../addon/hsse/hsse.php:255
|
||||
#: ../../Zotlabs/Lib/ThreadItem.php:812 ../../Zotlabs/Module/Chat.php:218
|
||||
#: ../../include/conversation.php:1318 ../../addon/hsse/hsse.php:255
|
||||
#: ../../Zotlabs/Lib/ThreadItem.php:813 ../../Zotlabs/Module/Chat.php:218
|
||||
msgid "Encrypt text"
|
||||
msgstr ""
|
||||
|
||||
#: ../../include/conversation.php:1563
|
||||
#: ../../include/conversation.php:1564
|
||||
msgctxt "noun"
|
||||
msgid "Repeat"
|
||||
msgid_plural "Repeats"
|
||||
msgstr[0] ""
|
||||
msgstr[1] ""
|
||||
|
||||
#: ../../include/conversation.php:1566 ../../Zotlabs/Module/Photos.php:1134
|
||||
#: ../../include/conversation.php:1567 ../../Zotlabs/Module/Photos.php:1134
|
||||
msgctxt "noun"
|
||||
msgid "Dislike"
|
||||
msgid_plural "Dislikes"
|
||||
msgstr[0] ""
|
||||
msgstr[1] ""
|
||||
|
||||
#: ../../include/conversation.php:1569
|
||||
#: ../../include/conversation.php:1570
|
||||
msgctxt "noun"
|
||||
msgid "Attending"
|
||||
msgid_plural "Attending"
|
||||
msgstr[0] ""
|
||||
msgstr[1] ""
|
||||
|
||||
#: ../../include/conversation.php:1572
|
||||
#: ../../include/conversation.php:1573
|
||||
msgctxt "noun"
|
||||
msgid "Not Attending"
|
||||
msgid_plural "Not Attending"
|
||||
msgstr[0] ""
|
||||
msgstr[1] ""
|
||||
|
||||
#: ../../include/conversation.php:1575
|
||||
#: ../../include/conversation.php:1576
|
||||
msgctxt "noun"
|
||||
msgid "Undecided"
|
||||
msgid_plural "Undecided"
|
||||
@@ -3728,7 +3732,7 @@ msgid "Account '%s' deleted"
|
||||
msgstr ""
|
||||
|
||||
#: ../../include/bbcode.php:234 ../../include/bbcode.php:994
|
||||
#: ../../include/bbcode.php:1659 ../../include/bbcode.php:1667
|
||||
#: ../../include/bbcode.php:1663 ../../include/bbcode.php:1671
|
||||
msgid "Image/photo"
|
||||
msgstr ""
|
||||
|
||||
@@ -3784,12 +3788,12 @@ msgstr ""
|
||||
msgid "View summary"
|
||||
msgstr ""
|
||||
|
||||
#: ../../include/bbcode.php:1127 ../../include/bbcode.php:1312
|
||||
#: ../../include/bbcode.php:1127 ../../include/bbcode.php:1314
|
||||
#: ../../addon/wiki/Lib/NativeWikiPage.php:634
|
||||
msgid "Different viewers will see this text differently"
|
||||
msgstr ""
|
||||
|
||||
#: ../../include/bbcode.php:1635
|
||||
#: ../../include/bbcode.php:1639
|
||||
msgid "$1 wrote:"
|
||||
msgstr ""
|
||||
|
||||
@@ -3802,7 +3806,7 @@ msgid ""
|
||||
"Cannot create a duplicate channel identifier on this system. Import failed."
|
||||
msgstr ""
|
||||
|
||||
#: ../../include/import.php:78 ../../addon/diaspora/import_diaspora.php:43
|
||||
#: ../../include/import.php:78 ../../addon/diaspora/import_diaspora.php:56
|
||||
msgid "Unable to create a unique channel address. Import failed."
|
||||
msgstr ""
|
||||
|
||||
@@ -4621,18 +4625,17 @@ msgstr ""
|
||||
msgid "Edit Card"
|
||||
msgstr ""
|
||||
|
||||
#: ../../addon/startpage/Mod_Startpage.php:60
|
||||
#: ../../addon/startpage/Mod_Startpage.php:61
|
||||
msgid "Page to load after login"
|
||||
msgstr ""
|
||||
|
||||
#: ../../addon/startpage/Mod_Startpage.php:60
|
||||
#: ../../addon/startpage/Mod_Startpage.php:63
|
||||
msgid ""
|
||||
"Examples: "apps", "network?f=&gid=37" (privacy "
|
||||
"collection), "channel" or "notifications/system" (leave "
|
||||
"blank for default network page (grid)."
|
||||
"Examples: \"apps\", \"network?f=&gid=37\" (privacy collection), \"channel\" "
|
||||
"or \"notifications/system\" (leave blank for default.)"
|
||||
msgstr ""
|
||||
|
||||
#: ../../addon/startpage/Mod_Startpage.php:68
|
||||
#: ../../addon/startpage/Mod_Startpage.php:72
|
||||
msgid "Startpage"
|
||||
msgstr ""
|
||||
|
||||
@@ -4708,12 +4711,12 @@ msgstr ""
|
||||
msgid "Activitypub Protocol"
|
||||
msgstr ""
|
||||
|
||||
#: ../../addon/pubcrawl/pubcrawl.php:1080 ../../addon/diaspora/diaspora.php:415
|
||||
#: ../../addon/pubcrawl/pubcrawl.php:1099 ../../addon/diaspora/diaspora.php:415
|
||||
#: ../../Zotlabs/Module/Contactedit.php:494
|
||||
msgid "Refresh failed"
|
||||
msgstr ""
|
||||
|
||||
#: ../../addon/pubcrawl/pubcrawl.php:1087 ../../addon/diaspora/diaspora.php:420
|
||||
#: ../../addon/pubcrawl/pubcrawl.php:1106 ../../addon/diaspora/diaspora.php:420
|
||||
#: ../../Zotlabs/Module/Contactedit.php:491
|
||||
msgid "Refresh succeeded"
|
||||
msgstr ""
|
||||
@@ -4788,15 +4791,23 @@ msgstr ""
|
||||
msgid "Diaspora relay could not be imported"
|
||||
msgstr ""
|
||||
|
||||
#: ../../addon/diaspora/diaspora.php:1106
|
||||
#: ../../addon/diaspora/diaspora.php:1110
|
||||
msgid "No subject"
|
||||
msgstr ""
|
||||
|
||||
#: ../../addon/diaspora/import_diaspora.php:18
|
||||
#: ../../addon/diaspora/import_diaspora.php:16
|
||||
msgid "No account to import to."
|
||||
msgstr ""
|
||||
|
||||
#: ../../addon/diaspora/import_diaspora.php:21
|
||||
msgid "Incompatible data version - aborting"
|
||||
msgstr ""
|
||||
|
||||
#: ../../addon/diaspora/import_diaspora.php:27
|
||||
msgid "No username found in import file."
|
||||
msgstr ""
|
||||
|
||||
#: ../../addon/diaspora/import_diaspora.php:140
|
||||
#: ../../addon/diaspora/import_diaspora.php:170
|
||||
msgid "Import completed."
|
||||
msgstr ""
|
||||
|
||||
@@ -7384,60 +7395,60 @@ msgstr ""
|
||||
msgid "This is you"
|
||||
msgstr ""
|
||||
|
||||
#: ../../Zotlabs/Lib/ThreadItem.php:805
|
||||
#: ../../Zotlabs/Lib/ThreadItem.php:806
|
||||
msgid "Image"
|
||||
msgstr ""
|
||||
|
||||
#: ../../Zotlabs/Lib/ThreadItem.php:807
|
||||
#: ../../Zotlabs/Lib/ThreadItem.php:808
|
||||
msgid "Insert Link"
|
||||
msgstr ""
|
||||
|
||||
#: ../../Zotlabs/Lib/ThreadItem.php:808
|
||||
#: ../../Zotlabs/Lib/ThreadItem.php:809
|
||||
msgid "Video"
|
||||
msgstr ""
|
||||
|
||||
#: ../../Zotlabs/Lib/ThreadItem.php:817
|
||||
#: ../../Zotlabs/Lib/ThreadItem.php:818
|
||||
msgid "Your full name (required)"
|
||||
msgstr ""
|
||||
|
||||
#: ../../Zotlabs/Lib/ThreadItem.php:818
|
||||
#: ../../Zotlabs/Lib/ThreadItem.php:819
|
||||
msgid "Your email address (required)"
|
||||
msgstr ""
|
||||
|
||||
#: ../../Zotlabs/Lib/ThreadItem.php:819
|
||||
#: ../../Zotlabs/Lib/ThreadItem.php:820
|
||||
msgid "Your website URL (optional)"
|
||||
msgstr ""
|
||||
|
||||
#: ../../Zotlabs/Lib/Libzot.php:688
|
||||
#: ../../Zotlabs/Lib/Libzot.php:693
|
||||
msgid "Unable to verify channel signature"
|
||||
msgstr ""
|
||||
|
||||
#: ../../Zotlabs/Lib/Activity.php:2257
|
||||
#: ../../Zotlabs/Lib/Activity.php:2259
|
||||
#, php-format
|
||||
msgid "Likes %1$s's %2$s"
|
||||
msgstr ""
|
||||
|
||||
#: ../../Zotlabs/Lib/Activity.php:2260
|
||||
#: ../../Zotlabs/Lib/Activity.php:2262
|
||||
#, php-format
|
||||
msgid "Doesn't like %1$s's %2$s"
|
||||
msgstr ""
|
||||
|
||||
#: ../../Zotlabs/Lib/Activity.php:2266
|
||||
#: ../../Zotlabs/Lib/Activity.php:2268
|
||||
#, php-format
|
||||
msgid "Will attend %s's event"
|
||||
msgstr ""
|
||||
|
||||
#: ../../Zotlabs/Lib/Activity.php:2269
|
||||
#: ../../Zotlabs/Lib/Activity.php:2271
|
||||
#, php-format
|
||||
msgid "Will not attend %s's event"
|
||||
msgstr ""
|
||||
|
||||
#: ../../Zotlabs/Lib/Activity.php:2272
|
||||
#: ../../Zotlabs/Lib/Activity.php:2274
|
||||
#, php-format
|
||||
msgid "May attend %s's event"
|
||||
msgstr ""
|
||||
|
||||
#: ../../Zotlabs/Lib/Activity.php:2275
|
||||
#: ../../Zotlabs/Lib/Activity.php:2277
|
||||
#, php-format
|
||||
msgid "May not attend %s's event"
|
||||
msgstr ""
|
||||
@@ -8696,11 +8707,11 @@ msgstr ""
|
||||
msgid "Edit Webpage"
|
||||
msgstr ""
|
||||
|
||||
#: ../../Zotlabs/Module/Sse_bs.php:631
|
||||
#: ../../Zotlabs/Module/Sse_bs.php:633
|
||||
msgid "Private forum"
|
||||
msgstr ""
|
||||
|
||||
#: ../../Zotlabs/Module/Sse_bs.php:631
|
||||
#: ../../Zotlabs/Module/Sse_bs.php:633
|
||||
msgid "Public forum"
|
||||
msgstr ""
|
||||
|
||||
@@ -9808,7 +9819,7 @@ msgstr ""
|
||||
msgid "Unable to locate original post."
|
||||
msgstr ""
|
||||
|
||||
#: ../../Zotlabs/Module/Item.php:539
|
||||
#: ../../Zotlabs/Module/Item.php:541
|
||||
msgid "Empty post discarded."
|
||||
msgstr ""
|
||||
|
||||
@@ -13724,8 +13735,8 @@ msgstr ""
|
||||
|
||||
#: ../../Zotlabs/Module/Setup.php:496
|
||||
msgid ""
|
||||
"If running under Windows, please see \"http://www.php.net/manual/en/openssl."
|
||||
"installation.php\"."
|
||||
"If running under Windows, please see \"http://www.php.net/manual/en/"
|
||||
"openssl.installation.php\"."
|
||||
msgstr ""
|
||||
|
||||
#: ../../Zotlabs/Module/Setup.php:499
|
||||
@@ -13963,8 +13974,8 @@ msgstr ""
|
||||
|
||||
#: ../../Zotlabs/Module/Setup.php:709
|
||||
msgid ""
|
||||
"Url rewrite in .htaccess is not working. Check your server configuration."
|
||||
"Test: "
|
||||
"Url rewrite in .htaccess is not working. Check your server "
|
||||
"configuration.Test: "
|
||||
msgstr ""
|
||||
|
||||
#: ../../Zotlabs/Module/Setup.php:712
|
||||
|
||||
2
vendor/bin/naturalselection
vendored
2
vendor/bin/naturalselection
vendored
@@ -34,4 +34,4 @@ if [ -n "$bashSource" ]; then
|
||||
fi
|
||||
fi
|
||||
|
||||
"${dir}/naturalselection" "$@"
|
||||
exec "${dir}/naturalselection" "$@"
|
||||
|
||||
2
vendor/bin/sabredav
vendored
2
vendor/bin/sabredav
vendored
@@ -34,4 +34,4 @@ if [ -n "$bashSource" ]; then
|
||||
fi
|
||||
fi
|
||||
|
||||
"${dir}/sabredav" "$@"
|
||||
exec "${dir}/sabredav" "$@"
|
||||
|
||||
18
vendor/brick/math/CHANGELOG.md
vendored
18
vendor/brick/math/CHANGELOG.md
vendored
@@ -2,6 +2,24 @@
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
## [0.12.1](https://github.com/brick/math/releases/tag/0.12.1) - 2023-11-29
|
||||
|
||||
⚡️ **Performance improvements**
|
||||
|
||||
- `BigNumber::of()` is now faster, thanks to [@SebastienDug](https://github.com/SebastienDug) in [#77](https://github.com/brick/math/pull/77).
|
||||
|
||||
## [0.12.0](https://github.com/brick/math/releases/tag/0.12.0) - 2023-11-26
|
||||
|
||||
💥 **Breaking changes**
|
||||
|
||||
- Minimum PHP version is now 8.1
|
||||
- `RoundingMode` is now an `enum`; if you're type-hinting rounding modes, you need to type-hint against `RoundingMode` instead of `int` now
|
||||
- `BigNumber` classes do not implement the `Serializable` interface anymore (they use the [new custom object serialization mechanism](https://wiki.php.net/rfc/custom_object_serialization))
|
||||
- The following breaking changes only affect you if you're creating your own `BigNumber` subclasses:
|
||||
- the return type of `BigNumber::of()` is now `static`
|
||||
- `BigNumber` has a new abstract method `from()`
|
||||
- all `public` and `protected` functions of `BigNumber` are now `final`
|
||||
|
||||
## [0.11.0](https://github.com/brick/math/releases/tag/0.11.0) - 2023-01-16
|
||||
|
||||
💥 **Breaking changes**
|
||||
|
||||
13
vendor/brick/math/composer.json
vendored
13
vendor/brick/math/composer.json
vendored
@@ -5,21 +5,26 @@
|
||||
"keywords": [
|
||||
"Brick",
|
||||
"Math",
|
||||
"Mathematics",
|
||||
"Arbitrary-precision",
|
||||
"Arithmetic",
|
||||
"BigInteger",
|
||||
"BigDecimal",
|
||||
"BigRational",
|
||||
"Bignum"
|
||||
"BigNumber",
|
||||
"Bignum",
|
||||
"Decimal",
|
||||
"Rational",
|
||||
"Integer"
|
||||
],
|
||||
"license": "MIT",
|
||||
"require": {
|
||||
"php": "^8.0"
|
||||
"php": "^8.1"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^9.0",
|
||||
"phpunit/phpunit": "^10.1",
|
||||
"php-coveralls/php-coveralls": "^2.2",
|
||||
"vimeo/psalm": "5.0.0"
|
||||
"vimeo/psalm": "5.16.0"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
|
||||
54
vendor/brick/math/src/BigDecimal.php
vendored
54
vendor/brick/math/src/BigDecimal.php
vendored
@@ -23,14 +23,14 @@ final class BigDecimal extends BigNumber
|
||||
* No leading zero must be present.
|
||||
* No leading minus sign must be present if the value is 0.
|
||||
*/
|
||||
private string $value;
|
||||
private readonly string $value;
|
||||
|
||||
/**
|
||||
* The scale (number of digits after the decimal point) of this decimal number.
|
||||
*
|
||||
* This must be zero or more.
|
||||
*/
|
||||
private int $scale;
|
||||
private readonly int $scale;
|
||||
|
||||
/**
|
||||
* Protected constructor. Use a factory method to obtain an instance.
|
||||
@@ -45,15 +45,11 @@ final class BigDecimal extends BigNumber
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a BigDecimal of the given value.
|
||||
*
|
||||
* @throws MathException If the value cannot be converted to a BigDecimal.
|
||||
*
|
||||
* @psalm-pure
|
||||
*/
|
||||
public static function of(BigNumber|int|float|string $value) : BigDecimal
|
||||
protected static function from(BigNumber $number): static
|
||||
{
|
||||
return parent::of($value)->toBigDecimal();
|
||||
return $number->toBigDecimal();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -223,12 +219,12 @@ final class BigDecimal extends BigNumber
|
||||
*
|
||||
* @param BigNumber|int|float|string $that The divisor.
|
||||
* @param int|null $scale The desired scale, or null to use the scale of this number.
|
||||
* @param int $roundingMode An optional rounding mode.
|
||||
* @param RoundingMode $roundingMode An optional rounding mode, defaults to UNNECESSARY.
|
||||
*
|
||||
* @throws \InvalidArgumentException If the scale or rounding mode is invalid.
|
||||
* @throws MathException If the number is invalid, is zero, or rounding was necessary.
|
||||
*/
|
||||
public function dividedBy(BigNumber|int|float|string $that, ?int $scale = null, int $roundingMode = RoundingMode::UNNECESSARY) : BigDecimal
|
||||
public function dividedBy(BigNumber|int|float|string $that, ?int $scale = null, RoundingMode $roundingMode = RoundingMode::UNNECESSARY) : BigDecimal
|
||||
{
|
||||
$that = BigDecimal::of($that);
|
||||
|
||||
@@ -324,7 +320,7 @@ final class BigDecimal extends BigNumber
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the quotient of the division of this number by this given one.
|
||||
* Returns the quotient of the division of this number by the given one.
|
||||
*
|
||||
* The quotient has a scale of `0`.
|
||||
*
|
||||
@@ -349,7 +345,7 @@ final class BigDecimal extends BigNumber
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the remainder of the division of this number by this given one.
|
||||
* Returns the remainder of the division of this number by the given one.
|
||||
*
|
||||
* The remainder has a scale of `max($this->scale, $that->scale)`.
|
||||
*
|
||||
@@ -384,6 +380,8 @@ final class BigDecimal extends BigNumber
|
||||
*
|
||||
* @return BigDecimal[] An array containing the quotient and the remainder.
|
||||
*
|
||||
* @psalm-return array{BigDecimal, BigDecimal}
|
||||
*
|
||||
* @throws MathException If the divisor is not a valid decimal number, or is zero.
|
||||
*/
|
||||
public function quotientAndRemainder(BigNumber|int|float|string $that) : array
|
||||
@@ -631,7 +629,7 @@ final class BigDecimal extends BigNumber
|
||||
return self::newBigRational($numerator, $denominator, false);
|
||||
}
|
||||
|
||||
public function toScale(int $scale, int $roundingMode = RoundingMode::UNNECESSARY) : BigDecimal
|
||||
public function toScale(int $scale, RoundingMode $roundingMode = RoundingMode::UNNECESSARY) : BigDecimal
|
||||
{
|
||||
if ($scale === $this->scale) {
|
||||
return $this;
|
||||
@@ -693,36 +691,6 @@ final class BigDecimal extends BigNumber
|
||||
$this->scale = $data['scale'];
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is required by interface Serializable and SHOULD NOT be accessed directly.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
public function serialize() : string
|
||||
{
|
||||
return $this->value . ':' . $this->scale;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is only here to implement interface Serializable and cannot be accessed directly.
|
||||
*
|
||||
* @internal
|
||||
* @psalm-suppress RedundantPropertyInitializationCheck
|
||||
*
|
||||
* @throws \LogicException
|
||||
*/
|
||||
public function unserialize($value) : void
|
||||
{
|
||||
if (isset($this->value)) {
|
||||
throw new \LogicException('unserialize() is an internal function, it must not be called directly.');
|
||||
}
|
||||
|
||||
[$value, $scale] = \explode(':', $value);
|
||||
|
||||
$this->value = $value;
|
||||
$this->scale = (int) $scale;
|
||||
}
|
||||
|
||||
/**
|
||||
* Puts the internal values of the given decimal numbers on the same scale.
|
||||
*
|
||||
|
||||
48
vendor/brick/math/src/BigInteger.php
vendored
48
vendor/brick/math/src/BigInteger.php
vendored
@@ -27,7 +27,7 @@ final class BigInteger extends BigNumber
|
||||
* No leading zeros must be present.
|
||||
* No leading minus sign must be present if the number is zero.
|
||||
*/
|
||||
private string $value;
|
||||
private readonly string $value;
|
||||
|
||||
/**
|
||||
* Protected constructor. Use a factory method to obtain an instance.
|
||||
@@ -40,15 +40,11 @@ final class BigInteger extends BigNumber
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a BigInteger of the given value.
|
||||
*
|
||||
* @throws MathException If the value cannot be converted to a BigInteger.
|
||||
*
|
||||
* @psalm-pure
|
||||
*/
|
||||
public static function of(BigNumber|int|float|string $value) : BigInteger
|
||||
protected static function from(BigNumber $number): static
|
||||
{
|
||||
return parent::of($value)->toBigInteger();
|
||||
return $number->toBigInteger();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -225,9 +221,10 @@ final class BigInteger extends BigNumber
|
||||
}
|
||||
|
||||
if ($randomBytesGenerator === null) {
|
||||
$randomBytesGenerator = 'random_bytes';
|
||||
$randomBytesGenerator = random_bytes(...);
|
||||
}
|
||||
|
||||
/** @var int<1, max> $byteLength */
|
||||
$byteLength = \intdiv($numBits - 1, 8) + 1;
|
||||
|
||||
$extraBits = ($byteLength * 8 - $numBits);
|
||||
@@ -429,12 +426,12 @@ final class BigInteger extends BigNumber
|
||||
* Returns the result of the division of this number by the given one.
|
||||
*
|
||||
* @param BigNumber|int|float|string $that The divisor. Must be convertible to a BigInteger.
|
||||
* @param int $roundingMode An optional rounding mode.
|
||||
* @param RoundingMode $roundingMode An optional rounding mode, defaults to UNNECESSARY.
|
||||
*
|
||||
* @throws MathException If the divisor is not a valid number, is not convertible to a BigInteger, is zero,
|
||||
* or RoundingMode::UNNECESSARY is used and the remainder is not zero.
|
||||
*/
|
||||
public function dividedBy(BigNumber|int|float|string $that, int $roundingMode = RoundingMode::UNNECESSARY) : BigInteger
|
||||
public function dividedBy(BigNumber|int|float|string $that, RoundingMode $roundingMode = RoundingMode::UNNECESSARY) : BigInteger
|
||||
{
|
||||
$that = BigInteger::of($that);
|
||||
|
||||
@@ -534,6 +531,8 @@ final class BigInteger extends BigNumber
|
||||
*
|
||||
* @return BigInteger[] An array containing the quotient and the remainder.
|
||||
*
|
||||
* @psalm-return array{BigInteger, BigInteger}
|
||||
*
|
||||
* @throws DivisionByZeroException If the divisor is zero.
|
||||
*/
|
||||
public function quotientAndRemainder(BigNumber|int|float|string $that) : array
|
||||
@@ -888,7 +887,7 @@ final class BigInteger extends BigNumber
|
||||
return self::newBigRational($this, BigInteger::one(), false);
|
||||
}
|
||||
|
||||
public function toScale(int $scale, int $roundingMode = RoundingMode::UNNECESSARY) : BigDecimal
|
||||
public function toScale(int $scale, RoundingMode $roundingMode = RoundingMode::UNNECESSARY) : BigDecimal
|
||||
{
|
||||
return $this->toBigDecimal()->toScale($scale, $roundingMode);
|
||||
}
|
||||
@@ -1049,31 +1048,4 @@ final class BigInteger extends BigNumber
|
||||
|
||||
$this->value = $data['value'];
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is required by interface Serializable and SHOULD NOT be accessed directly.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
public function serialize() : string
|
||||
{
|
||||
return $this->value;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is only here to implement interface Serializable and cannot be accessed directly.
|
||||
*
|
||||
* @internal
|
||||
* @psalm-suppress RedundantPropertyInitializationCheck
|
||||
*
|
||||
* @throws \LogicException
|
||||
*/
|
||||
public function unserialize($value) : void
|
||||
{
|
||||
if (isset($this->value)) {
|
||||
throw new \LogicException('unserialize() is an internal function, it must not be called directly.');
|
||||
}
|
||||
|
||||
$this->value = $value;
|
||||
}
|
||||
}
|
||||
|
||||
247
vendor/brick/math/src/BigNumber.php
vendored
247
vendor/brick/math/src/BigNumber.php
vendored
@@ -14,26 +14,29 @@ use Brick\Math\Exception\RoundingNecessaryException;
|
||||
*
|
||||
* @psalm-immutable
|
||||
*/
|
||||
abstract class BigNumber implements \Serializable, \JsonSerializable
|
||||
abstract class BigNumber implements \JsonSerializable
|
||||
{
|
||||
/**
|
||||
* The regular expression used to parse integer, decimal and rational numbers.
|
||||
* The regular expression used to parse integer or decimal numbers.
|
||||
*/
|
||||
private const PARSE_REGEXP =
|
||||
private const PARSE_REGEXP_NUMERICAL =
|
||||
'/^' .
|
||||
'(?<sign>[\-\+])?' .
|
||||
'(?:' .
|
||||
'(?:' .
|
||||
'(?<integral>[0-9]+)?' .
|
||||
'(?<point>\.)?' .
|
||||
'(?<fractional>[0-9]+)?' .
|
||||
'(?:[eE](?<exponent>[\-\+]?[0-9]+))?' .
|
||||
')|(?:' .
|
||||
'(?<numerator>[0-9]+)' .
|
||||
'\/?' .
|
||||
'(?<denominator>[0-9]+)' .
|
||||
')' .
|
||||
')' .
|
||||
'(?<integral>[0-9]+)?' .
|
||||
'(?<point>\.)?' .
|
||||
'(?<fractional>[0-9]+)?' .
|
||||
'(?:[eE](?<exponent>[\-\+]?[0-9]+))?' .
|
||||
'$/';
|
||||
|
||||
/**
|
||||
* The regular expression used to parse rational numbers.
|
||||
*/
|
||||
private const PARSE_REGEXP_RATIONAL =
|
||||
'/^' .
|
||||
'(?<sign>[\-\+])?' .
|
||||
'(?<numerator>[0-9]+)' .
|
||||
'\/?' .
|
||||
'(?<denominator>[0-9]+)' .
|
||||
'$/';
|
||||
|
||||
/**
|
||||
@@ -53,7 +56,24 @@ abstract class BigNumber implements \Serializable, \JsonSerializable
|
||||
*
|
||||
* @psalm-pure
|
||||
*/
|
||||
public static function of(BigNumber|int|float|string $value) : BigNumber
|
||||
final public static function of(BigNumber|int|float|string $value) : static
|
||||
{
|
||||
$value = self::_of($value);
|
||||
|
||||
if (static::class === BigNumber::class) {
|
||||
// https://github.com/vimeo/psalm/issues/10309
|
||||
assert($value instanceof static);
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
return static::from($value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @psalm-pure
|
||||
*/
|
||||
private static function _of(BigNumber|int|float|string $value) : BigNumber
|
||||
{
|
||||
if ($value instanceof BigNumber) {
|
||||
return $value;
|
||||
@@ -63,34 +83,25 @@ abstract class BigNumber implements \Serializable, \JsonSerializable
|
||||
return new BigInteger((string) $value);
|
||||
}
|
||||
|
||||
$value = \is_float($value) ? self::floatToString($value) : $value;
|
||||
|
||||
$throw = static function() use ($value) : void {
|
||||
throw new NumberFormatException(\sprintf(
|
||||
'The given value "%s" does not represent a valid number.',
|
||||
$value
|
||||
));
|
||||
};
|
||||
|
||||
if (\preg_match(self::PARSE_REGEXP, $value, $matches) !== 1) {
|
||||
$throw();
|
||||
if (is_float($value)) {
|
||||
$value = (string) $value;
|
||||
}
|
||||
|
||||
$getMatch = static fn(string $value): ?string => (($matches[$value] ?? '') !== '') ? $matches[$value] : null;
|
||||
|
||||
$sign = $getMatch('sign');
|
||||
$numerator = $getMatch('numerator');
|
||||
$denominator = $getMatch('denominator');
|
||||
|
||||
if ($numerator !== null) {
|
||||
assert($denominator !== null);
|
||||
|
||||
if ($sign !== null) {
|
||||
$numerator = $sign . $numerator;
|
||||
if (str_contains($value, '/')) {
|
||||
// Rational number
|
||||
if (\preg_match(self::PARSE_REGEXP_RATIONAL, $value, $matches, PREG_UNMATCHED_AS_NULL) !== 1) {
|
||||
throw NumberFormatException::invalidFormat($value);
|
||||
}
|
||||
|
||||
$numerator = self::cleanUp($numerator);
|
||||
$denominator = self::cleanUp($denominator);
|
||||
$sign = $matches['sign'];
|
||||
$numerator = $matches['numerator'];
|
||||
$denominator = $matches['denominator'];
|
||||
|
||||
assert($numerator !== null);
|
||||
assert($denominator !== null);
|
||||
|
||||
$numerator = self::cleanUp($sign, $numerator);
|
||||
$denominator = self::cleanUp(null, $denominator);
|
||||
|
||||
if ($denominator === '0') {
|
||||
throw DivisionByZeroException::denominatorMustNotBeZero();
|
||||
@@ -101,67 +112,62 @@ abstract class BigNumber implements \Serializable, \JsonSerializable
|
||||
new BigInteger($denominator),
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
$point = $getMatch('point');
|
||||
$integral = $getMatch('integral');
|
||||
$fractional = $getMatch('fractional');
|
||||
$exponent = $getMatch('exponent');
|
||||
|
||||
if ($integral === null && $fractional === null) {
|
||||
$throw();
|
||||
}
|
||||
|
||||
if ($integral === null) {
|
||||
$integral = '0';
|
||||
}
|
||||
|
||||
if ($point !== null || $exponent !== null) {
|
||||
$fractional = ($fractional ?? '');
|
||||
$exponent = ($exponent !== null) ? (int) $exponent : 0;
|
||||
|
||||
if ($exponent === PHP_INT_MIN || $exponent === PHP_INT_MAX) {
|
||||
throw new NumberFormatException('Exponent too large.');
|
||||
} else {
|
||||
// Integer or decimal number
|
||||
if (\preg_match(self::PARSE_REGEXP_NUMERICAL, $value, $matches, PREG_UNMATCHED_AS_NULL) !== 1) {
|
||||
throw NumberFormatException::invalidFormat($value);
|
||||
}
|
||||
|
||||
$unscaledValue = self::cleanUp(($sign ?? ''). $integral . $fractional);
|
||||
$sign = $matches['sign'];
|
||||
$point = $matches['point'];
|
||||
$integral = $matches['integral'];
|
||||
$fractional = $matches['fractional'];
|
||||
$exponent = $matches['exponent'];
|
||||
|
||||
$scale = \strlen($fractional) - $exponent;
|
||||
if ($integral === null && $fractional === null) {
|
||||
throw NumberFormatException::invalidFormat($value);
|
||||
}
|
||||
|
||||
if ($scale < 0) {
|
||||
if ($unscaledValue !== '0') {
|
||||
$unscaledValue .= \str_repeat('0', - $scale);
|
||||
if ($integral === null) {
|
||||
$integral = '0';
|
||||
}
|
||||
|
||||
if ($point !== null || $exponent !== null) {
|
||||
$fractional = ($fractional ?? '');
|
||||
$exponent = ($exponent !== null) ? (int)$exponent : 0;
|
||||
|
||||
if ($exponent === PHP_INT_MIN || $exponent === PHP_INT_MAX) {
|
||||
throw new NumberFormatException('Exponent too large.');
|
||||
}
|
||||
$scale = 0;
|
||||
|
||||
$unscaledValue = self::cleanUp($sign, $integral . $fractional);
|
||||
|
||||
$scale = \strlen($fractional) - $exponent;
|
||||
|
||||
if ($scale < 0) {
|
||||
if ($unscaledValue !== '0') {
|
||||
$unscaledValue .= \str_repeat('0', -$scale);
|
||||
}
|
||||
$scale = 0;
|
||||
}
|
||||
|
||||
return new BigDecimal($unscaledValue, $scale);
|
||||
}
|
||||
|
||||
return new BigDecimal($unscaledValue, $scale);
|
||||
$integral = self::cleanUp($sign, $integral);
|
||||
|
||||
return new BigInteger($integral);
|
||||
}
|
||||
|
||||
$integral = self::cleanUp(($sign ?? '') . $integral);
|
||||
|
||||
return new BigInteger($integral);
|
||||
}
|
||||
|
||||
/**
|
||||
* Safely converts float to string, avoiding locale-dependent issues.
|
||||
* Overridden by subclasses to convert a BigNumber to an instance of the subclass.
|
||||
*
|
||||
* @see https://github.com/brick/math/pull/20
|
||||
* @throws MathException If the value cannot be converted.
|
||||
*
|
||||
* @psalm-pure
|
||||
* @psalm-suppress ImpureFunctionCall
|
||||
*/
|
||||
private static function floatToString(float $float) : string
|
||||
{
|
||||
$currentLocale = \setlocale(LC_NUMERIC, '0');
|
||||
\setlocale(LC_NUMERIC, 'C');
|
||||
|
||||
$result = (string) $float;
|
||||
|
||||
\setlocale(LC_NUMERIC, $currentLocale);
|
||||
|
||||
return $result;
|
||||
}
|
||||
abstract protected static function from(BigNumber $number): static;
|
||||
|
||||
/**
|
||||
* Proxy method to access BigInteger's protected constructor from sibling classes.
|
||||
@@ -169,7 +175,7 @@ abstract class BigNumber implements \Serializable, \JsonSerializable
|
||||
* @internal
|
||||
* @psalm-pure
|
||||
*/
|
||||
protected function newBigInteger(string $value) : BigInteger
|
||||
final protected function newBigInteger(string $value) : BigInteger
|
||||
{
|
||||
return new BigInteger($value);
|
||||
}
|
||||
@@ -180,7 +186,7 @@ abstract class BigNumber implements \Serializable, \JsonSerializable
|
||||
* @internal
|
||||
* @psalm-pure
|
||||
*/
|
||||
protected function newBigDecimal(string $value, int $scale = 0) : BigDecimal
|
||||
final protected function newBigDecimal(string $value, int $scale = 0) : BigDecimal
|
||||
{
|
||||
return new BigDecimal($value, $scale);
|
||||
}
|
||||
@@ -191,7 +197,7 @@ abstract class BigNumber implements \Serializable, \JsonSerializable
|
||||
* @internal
|
||||
* @psalm-pure
|
||||
*/
|
||||
protected function newBigRational(BigInteger $numerator, BigInteger $denominator, bool $checkDenominator) : BigRational
|
||||
final protected function newBigRational(BigInteger $numerator, BigInteger $denominator, bool $checkDenominator) : BigRational
|
||||
{
|
||||
return new BigRational($numerator, $denominator, $checkDenominator);
|
||||
}
|
||||
@@ -205,11 +211,9 @@ abstract class BigNumber implements \Serializable, \JsonSerializable
|
||||
* @throws \InvalidArgumentException If no values are given.
|
||||
* @throws MathException If an argument is not valid.
|
||||
*
|
||||
* @psalm-suppress LessSpecificReturnStatement
|
||||
* @psalm-suppress MoreSpecificReturnType
|
||||
* @psalm-pure
|
||||
*/
|
||||
public static function min(BigNumber|int|float|string ...$values) : static
|
||||
final public static function min(BigNumber|int|float|string ...$values) : static
|
||||
{
|
||||
$min = null;
|
||||
|
||||
@@ -237,11 +241,9 @@ abstract class BigNumber implements \Serializable, \JsonSerializable
|
||||
* @throws \InvalidArgumentException If no values are given.
|
||||
* @throws MathException If an argument is not valid.
|
||||
*
|
||||
* @psalm-suppress LessSpecificReturnStatement
|
||||
* @psalm-suppress MoreSpecificReturnType
|
||||
* @psalm-pure
|
||||
*/
|
||||
public static function max(BigNumber|int|float|string ...$values) : static
|
||||
final public static function max(BigNumber|int|float|string ...$values) : static
|
||||
{
|
||||
$max = null;
|
||||
|
||||
@@ -271,7 +273,7 @@ abstract class BigNumber implements \Serializable, \JsonSerializable
|
||||
*
|
||||
* @psalm-pure
|
||||
*/
|
||||
public static function sum(BigNumber|int|float|string ...$values) : static
|
||||
final public static function sum(BigNumber|int|float|string ...$values) : static
|
||||
{
|
||||
/** @var static|null $sum */
|
||||
$sum = null;
|
||||
@@ -323,37 +325,28 @@ abstract class BigNumber implements \Serializable, \JsonSerializable
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes optional leading zeros and + sign from the given number.
|
||||
* Removes optional leading zeros and applies sign.
|
||||
*
|
||||
* @param string $number The number, validated as a non-empty string of digits with optional leading sign.
|
||||
* @param string|null $sign The sign, '+' or '-', optional. Null is allowed for convenience and treated as '+'.
|
||||
* @param string $number The number, validated as a non-empty string of digits.
|
||||
*
|
||||
* @psalm-pure
|
||||
*/
|
||||
private static function cleanUp(string $number) : string
|
||||
private static function cleanUp(string|null $sign, string $number) : string
|
||||
{
|
||||
$firstChar = $number[0];
|
||||
|
||||
if ($firstChar === '+' || $firstChar === '-') {
|
||||
$number = \substr($number, 1);
|
||||
}
|
||||
|
||||
$number = \ltrim($number, '0');
|
||||
|
||||
if ($number === '') {
|
||||
return '0';
|
||||
}
|
||||
|
||||
if ($firstChar === '-') {
|
||||
return '-' . $number;
|
||||
}
|
||||
|
||||
return $number;
|
||||
return $sign === '-' ? '-' . $number : $number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if this number is equal to the given one.
|
||||
*/
|
||||
public function isEqualTo(BigNumber|int|float|string $that) : bool
|
||||
final public function isEqualTo(BigNumber|int|float|string $that) : bool
|
||||
{
|
||||
return $this->compareTo($that) === 0;
|
||||
}
|
||||
@@ -361,7 +354,7 @@ abstract class BigNumber implements \Serializable, \JsonSerializable
|
||||
/**
|
||||
* Checks if this number is strictly lower than the given one.
|
||||
*/
|
||||
public function isLessThan(BigNumber|int|float|string $that) : bool
|
||||
final public function isLessThan(BigNumber|int|float|string $that) : bool
|
||||
{
|
||||
return $this->compareTo($that) < 0;
|
||||
}
|
||||
@@ -369,7 +362,7 @@ abstract class BigNumber implements \Serializable, \JsonSerializable
|
||||
/**
|
||||
* Checks if this number is lower than or equal to the given one.
|
||||
*/
|
||||
public function isLessThanOrEqualTo(BigNumber|int|float|string $that) : bool
|
||||
final public function isLessThanOrEqualTo(BigNumber|int|float|string $that) : bool
|
||||
{
|
||||
return $this->compareTo($that) <= 0;
|
||||
}
|
||||
@@ -377,7 +370,7 @@ abstract class BigNumber implements \Serializable, \JsonSerializable
|
||||
/**
|
||||
* Checks if this number is strictly greater than the given one.
|
||||
*/
|
||||
public function isGreaterThan(BigNumber|int|float|string $that) : bool
|
||||
final public function isGreaterThan(BigNumber|int|float|string $that) : bool
|
||||
{
|
||||
return $this->compareTo($that) > 0;
|
||||
}
|
||||
@@ -385,7 +378,7 @@ abstract class BigNumber implements \Serializable, \JsonSerializable
|
||||
/**
|
||||
* Checks if this number is greater than or equal to the given one.
|
||||
*/
|
||||
public function isGreaterThanOrEqualTo(BigNumber|int|float|string $that) : bool
|
||||
final public function isGreaterThanOrEqualTo(BigNumber|int|float|string $that) : bool
|
||||
{
|
||||
return $this->compareTo($that) >= 0;
|
||||
}
|
||||
@@ -393,7 +386,7 @@ abstract class BigNumber implements \Serializable, \JsonSerializable
|
||||
/**
|
||||
* Checks if this number equals zero.
|
||||
*/
|
||||
public function isZero() : bool
|
||||
final public function isZero() : bool
|
||||
{
|
||||
return $this->getSign() === 0;
|
||||
}
|
||||
@@ -401,7 +394,7 @@ abstract class BigNumber implements \Serializable, \JsonSerializable
|
||||
/**
|
||||
* Checks if this number is strictly negative.
|
||||
*/
|
||||
public function isNegative() : bool
|
||||
final public function isNegative() : bool
|
||||
{
|
||||
return $this->getSign() < 0;
|
||||
}
|
||||
@@ -409,7 +402,7 @@ abstract class BigNumber implements \Serializable, \JsonSerializable
|
||||
/**
|
||||
* Checks if this number is negative or zero.
|
||||
*/
|
||||
public function isNegativeOrZero() : bool
|
||||
final public function isNegativeOrZero() : bool
|
||||
{
|
||||
return $this->getSign() <= 0;
|
||||
}
|
||||
@@ -417,7 +410,7 @@ abstract class BigNumber implements \Serializable, \JsonSerializable
|
||||
/**
|
||||
* Checks if this number is strictly positive.
|
||||
*/
|
||||
public function isPositive() : bool
|
||||
final public function isPositive() : bool
|
||||
{
|
||||
return $this->getSign() > 0;
|
||||
}
|
||||
@@ -425,7 +418,7 @@ abstract class BigNumber implements \Serializable, \JsonSerializable
|
||||
/**
|
||||
* Checks if this number is positive or zero.
|
||||
*/
|
||||
public function isPositiveOrZero() : bool
|
||||
final public function isPositiveOrZero() : bool
|
||||
{
|
||||
return $this->getSign() >= 0;
|
||||
}
|
||||
@@ -433,6 +426,8 @@ abstract class BigNumber implements \Serializable, \JsonSerializable
|
||||
/**
|
||||
* Returns the sign of this number.
|
||||
*
|
||||
* @psalm-return -1|0|1
|
||||
*
|
||||
* @return int -1 if the number is negative, 0 if zero, 1 if positive.
|
||||
*/
|
||||
abstract public function getSign() : int;
|
||||
@@ -440,7 +435,9 @@ abstract class BigNumber implements \Serializable, \JsonSerializable
|
||||
/**
|
||||
* Compares this number to the given one.
|
||||
*
|
||||
* @return int [-1,0,1] If `$this` is lower than, equal to, or greater than `$that`.
|
||||
* @psalm-return -1|0|1
|
||||
*
|
||||
* @return int -1 if `$this` is lower than, 0 if equal to, 1 if greater than `$that`.
|
||||
*
|
||||
* @throws MathException If the number is not valid.
|
||||
*/
|
||||
@@ -468,13 +465,13 @@ abstract class BigNumber implements \Serializable, \JsonSerializable
|
||||
/**
|
||||
* Converts this number to a BigDecimal with the given scale, using rounding if necessary.
|
||||
*
|
||||
* @param int $scale The scale of the resulting `BigDecimal`.
|
||||
* @param int $roundingMode A `RoundingMode` constant.
|
||||
* @param int $scale The scale of the resulting `BigDecimal`.
|
||||
* @param RoundingMode $roundingMode An optional rounding mode, defaults to UNNECESSARY.
|
||||
*
|
||||
* @throws RoundingNecessaryException If this number cannot be converted to the given scale without rounding.
|
||||
* This only applies when RoundingMode::UNNECESSARY is used.
|
||||
*/
|
||||
abstract public function toScale(int $scale, int $roundingMode = RoundingMode::UNNECESSARY) : BigDecimal;
|
||||
abstract public function toScale(int $scale, RoundingMode $roundingMode = RoundingMode::UNNECESSARY) : BigDecimal;
|
||||
|
||||
/**
|
||||
* Returns the exact value of this number as a native integer.
|
||||
@@ -505,7 +502,7 @@ abstract class BigNumber implements \Serializable, \JsonSerializable
|
||||
*/
|
||||
abstract public function __toString() : string;
|
||||
|
||||
public function jsonSerialize() : string
|
||||
final public function jsonSerialize() : string
|
||||
{
|
||||
return $this->__toString();
|
||||
}
|
||||
|
||||
46
vendor/brick/math/src/BigRational.php
vendored
46
vendor/brick/math/src/BigRational.php
vendored
@@ -21,12 +21,12 @@ final class BigRational extends BigNumber
|
||||
/**
|
||||
* The numerator.
|
||||
*/
|
||||
private BigInteger $numerator;
|
||||
private readonly BigInteger $numerator;
|
||||
|
||||
/**
|
||||
* The denominator. Always strictly positive.
|
||||
*/
|
||||
private BigInteger $denominator;
|
||||
private readonly BigInteger $denominator;
|
||||
|
||||
/**
|
||||
* Protected constructor. Use a factory method to obtain an instance.
|
||||
@@ -55,15 +55,11 @@ final class BigRational extends BigNumber
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a BigRational of the given value.
|
||||
*
|
||||
* @throws MathException If the value cannot be converted to a BigRational.
|
||||
*
|
||||
* @psalm-pure
|
||||
*/
|
||||
public static function of(BigNumber|int|float|string $value) : BigRational
|
||||
protected static function from(BigNumber $number): static
|
||||
{
|
||||
return parent::of($value)->toBigRational();
|
||||
return $number->toBigRational();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -181,6 +177,8 @@ final class BigRational extends BigNumber
|
||||
* Returns the quotient and remainder of the division of the numerator by the denominator.
|
||||
*
|
||||
* @return BigInteger[]
|
||||
*
|
||||
* @psalm-return array{BigInteger, BigInteger}
|
||||
*/
|
||||
public function quotientAndRemainder() : array
|
||||
{
|
||||
@@ -353,7 +351,7 @@ final class BigRational extends BigNumber
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function toScale(int $scale, int $roundingMode = RoundingMode::UNNECESSARY) : BigDecimal
|
||||
public function toScale(int $scale, RoundingMode $roundingMode = RoundingMode::UNNECESSARY) : BigDecimal
|
||||
{
|
||||
return $this->numerator->toBigDecimal()->dividedBy($this->denominator, $scale, $roundingMode);
|
||||
}
|
||||
@@ -412,34 +410,4 @@ final class BigRational extends BigNumber
|
||||
$this->numerator = $data['numerator'];
|
||||
$this->denominator = $data['denominator'];
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is required by interface Serializable and SHOULD NOT be accessed directly.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
public function serialize() : string
|
||||
{
|
||||
return $this->numerator . '/' . $this->denominator;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is only here to implement interface Serializable and cannot be accessed directly.
|
||||
*
|
||||
* @internal
|
||||
* @psalm-suppress RedundantPropertyInitializationCheck
|
||||
*
|
||||
* @throws \LogicException
|
||||
*/
|
||||
public function unserialize($value) : void
|
||||
{
|
||||
if (isset($this->numerator)) {
|
||||
throw new \LogicException('unserialize() is an internal function, it must not be called directly.');
|
||||
}
|
||||
|
||||
[$numerator, $denominator] = \explode('/', $value);
|
||||
|
||||
$this->numerator = BigInteger::of($numerator);
|
||||
$this->denominator = BigInteger::of($denominator);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,14 @@ namespace Brick\Math\Exception;
|
||||
*/
|
||||
class NumberFormatException extends MathException
|
||||
{
|
||||
public static function invalidFormat(string $value) : self
|
||||
{
|
||||
return new self(\sprintf(
|
||||
'The given value "%s" does not represent a valid number.',
|
||||
$value,
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $char The failing character.
|
||||
*
|
||||
@@ -28,6 +36,6 @@ class NumberFormatException extends MathException
|
||||
$char = '"' . $char . '"';
|
||||
}
|
||||
|
||||
return new self(sprintf('Char %s is not a valid character in the given alphabet.', $char));
|
||||
return new self(\sprintf('Char %s is not a valid character in the given alphabet.', $char));
|
||||
}
|
||||
}
|
||||
|
||||
44
vendor/brick/math/src/Internal/Calculator.php
vendored
44
vendor/brick/math/src/Internal/Calculator.php
vendored
@@ -25,7 +25,7 @@ abstract class Calculator
|
||||
/**
|
||||
* The maximum exponent value allowed for the pow() method.
|
||||
*/
|
||||
public const MAX_POWER = 1000000;
|
||||
public const MAX_POWER = 1_000_000;
|
||||
|
||||
/**
|
||||
* The alphabet for converting from and to base 2 to 36, lowercase.
|
||||
@@ -128,7 +128,9 @@ abstract class Calculator
|
||||
/**
|
||||
* Compares two numbers.
|
||||
*
|
||||
* @return int [-1, 0, 1] If the first number is less than, equal to, or greater than the second number.
|
||||
* @psalm-return -1|0|1
|
||||
*
|
||||
* @return int -1 if the first number is less than, 0 if equal to, 1 if greater than the second number.
|
||||
*/
|
||||
final public function cmp(string $a, string $b) : int
|
||||
{
|
||||
@@ -428,16 +430,16 @@ abstract class Calculator
|
||||
*
|
||||
* Rounding is performed when the remainder of the division is not zero.
|
||||
*
|
||||
* @param string $a The dividend.
|
||||
* @param string $b The divisor, must not be zero.
|
||||
* @param int $roundingMode The rounding mode.
|
||||
* @param string $a The dividend.
|
||||
* @param string $b The divisor, must not be zero.
|
||||
* @param RoundingMode $roundingMode The rounding mode.
|
||||
*
|
||||
* @throws \InvalidArgumentException If the rounding mode is invalid.
|
||||
* @throws RoundingNecessaryException If RoundingMode::UNNECESSARY is provided but rounding is necessary.
|
||||
*
|
||||
* @psalm-suppress ImpureFunctionCall
|
||||
*/
|
||||
final public function divRound(string $a, string $b, int $roundingMode) : string
|
||||
final public function divRound(string $a, string $b, RoundingMode $roundingMode) : string
|
||||
{
|
||||
[$quotient, $remainder] = $this->divQR($a, $b);
|
||||
|
||||
@@ -571,27 +573,17 @@ abstract class Calculator
|
||||
$bBin = $this->twosComplement($bBin);
|
||||
}
|
||||
|
||||
switch ($operator) {
|
||||
case 'and':
|
||||
$value = $aBin & $bBin;
|
||||
$negative = ($aNeg and $bNeg);
|
||||
break;
|
||||
$value = match ($operator) {
|
||||
'and' => $aBin & $bBin,
|
||||
'or' => $aBin | $bBin,
|
||||
'xor' => $aBin ^ $bBin,
|
||||
};
|
||||
|
||||
case 'or':
|
||||
$value = $aBin | $bBin;
|
||||
$negative = ($aNeg or $bNeg);
|
||||
break;
|
||||
|
||||
case 'xor':
|
||||
$value = $aBin ^ $bBin;
|
||||
$negative = ($aNeg xor $bNeg);
|
||||
break;
|
||||
|
||||
// @codeCoverageIgnoreStart
|
||||
default:
|
||||
throw new \InvalidArgumentException('Invalid bitwise operator.');
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
$negative = match ($operator) {
|
||||
'and' => $aNeg and $bNeg,
|
||||
'or' => $aNeg or $bNeg,
|
||||
'xor' => $aNeg xor $bNeg,
|
||||
};
|
||||
|
||||
if ($negative) {
|
||||
$value = $this->twosComplement($value);
|
||||
|
||||
@@ -35,10 +35,6 @@ class BcMathCalculator extends Calculator
|
||||
return \bcdiv($a, $b, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @psalm-suppress InvalidNullableReturnType
|
||||
* @psalm-suppress NullableReturnStatement
|
||||
*/
|
||||
public function divR(string $a, string $b) : string
|
||||
{
|
||||
return \bcmod($a, $b, 0);
|
||||
@@ -49,8 +45,6 @@ class BcMathCalculator extends Calculator
|
||||
$q = \bcdiv($a, $b, 0);
|
||||
$r = \bcmod($a, $b, 0);
|
||||
|
||||
assert($r !== null);
|
||||
|
||||
return [$q, $r];
|
||||
}
|
||||
|
||||
@@ -64,10 +58,6 @@ class BcMathCalculator extends Calculator
|
||||
return \bcpowmod($base, $exp, $mod, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @psalm-suppress InvalidNullableReturnType
|
||||
* @psalm-suppress NullableReturnStatement
|
||||
*/
|
||||
public function sqrt(string $n) : string
|
||||
{
|
||||
return \bcsqrt($n, 0);
|
||||
|
||||
@@ -23,25 +23,18 @@ class NativeCalculator extends Calculator
|
||||
* Example: 32-bit: max number 1,999,999,999 (9 digits + carry)
|
||||
* 64-bit: max number 1,999,999,999,999,999,999 (18 digits + carry)
|
||||
*/
|
||||
private int $maxDigits;
|
||||
private readonly int $maxDigits;
|
||||
|
||||
/**
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
switch (PHP_INT_SIZE) {
|
||||
case 4:
|
||||
$this->maxDigits = 9;
|
||||
break;
|
||||
|
||||
case 8:
|
||||
$this->maxDigits = 18;
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new \RuntimeException('The platform is not 32-bit or 64-bit as expected.');
|
||||
}
|
||||
$this->maxDigits = match (PHP_INT_SIZE) {
|
||||
4 => 9,
|
||||
8 => 18,
|
||||
default => throw new \RuntimeException('The platform is not 32-bit or 64-bit as expected.')
|
||||
};
|
||||
}
|
||||
|
||||
public function add(string $a, string $b) : string
|
||||
@@ -161,10 +154,8 @@ class NativeCalculator extends Calculator
|
||||
if (is_int($nb)) {
|
||||
// the only division that may overflow is PHP_INT_MIN / -1,
|
||||
// which cannot happen here as we've already handled a divisor of -1 above.
|
||||
$q = intdiv($na, $nb);
|
||||
$r = $na % $nb;
|
||||
$q = ($na - $r) / $nb;
|
||||
|
||||
assert(is_int($q));
|
||||
|
||||
return [
|
||||
(string) $q,
|
||||
@@ -536,7 +527,7 @@ class NativeCalculator extends Calculator
|
||||
/**
|
||||
* Compares two non-signed large numbers.
|
||||
*
|
||||
* @return int [-1, 0, 1]
|
||||
* @psalm-return -1|0|1
|
||||
*/
|
||||
private function doCmp(string $a, string $b) : int
|
||||
{
|
||||
@@ -549,7 +540,7 @@ class NativeCalculator extends Calculator
|
||||
return $cmp;
|
||||
}
|
||||
|
||||
return \strcmp($a, $b) <=> 0; // enforce [-1, 0, 1]
|
||||
return \strcmp($a, $b) <=> 0; // enforce -1|0|1
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
31
vendor/brick/math/src/RoundingMode.php
vendored
31
vendor/brick/math/src/RoundingMode.php
vendored
@@ -13,24 +13,15 @@ namespace Brick\Math;
|
||||
* regardless the digits' contribution to the value of the number. In other words, considered
|
||||
* as a numerical value, the discarded fraction could have an absolute value greater than one.
|
||||
*/
|
||||
final class RoundingMode
|
||||
enum RoundingMode
|
||||
{
|
||||
/**
|
||||
* Private constructor. This class is not instantiable.
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
private function __construct()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that the requested operation has an exact result, hence no rounding is necessary.
|
||||
*
|
||||
* If this rounding mode is specified on an operation that yields a result that
|
||||
* cannot be represented at the requested scale, a RoundingNecessaryException is thrown.
|
||||
*/
|
||||
public const UNNECESSARY = 0;
|
||||
case UNNECESSARY;
|
||||
|
||||
/**
|
||||
* Rounds away from zero.
|
||||
@@ -38,7 +29,7 @@ final class RoundingMode
|
||||
* Always increments the digit prior to a nonzero discarded fraction.
|
||||
* Note that this rounding mode never decreases the magnitude of the calculated value.
|
||||
*/
|
||||
public const UP = 1;
|
||||
case UP;
|
||||
|
||||
/**
|
||||
* Rounds towards zero.
|
||||
@@ -46,7 +37,7 @@ final class RoundingMode
|
||||
* Never increments the digit prior to a discarded fraction (i.e., truncates).
|
||||
* Note that this rounding mode never increases the magnitude of the calculated value.
|
||||
*/
|
||||
public const DOWN = 2;
|
||||
case DOWN;
|
||||
|
||||
/**
|
||||
* Rounds towards positive infinity.
|
||||
@@ -54,7 +45,7 @@ final class RoundingMode
|
||||
* If the result is positive, behaves as for UP; if negative, behaves as for DOWN.
|
||||
* Note that this rounding mode never decreases the calculated value.
|
||||
*/
|
||||
public const CEILING = 3;
|
||||
case CEILING;
|
||||
|
||||
/**
|
||||
* Rounds towards negative infinity.
|
||||
@@ -62,7 +53,7 @@ final class RoundingMode
|
||||
* If the result is positive, behave as for DOWN; if negative, behave as for UP.
|
||||
* Note that this rounding mode never increases the calculated value.
|
||||
*/
|
||||
public const FLOOR = 4;
|
||||
case FLOOR;
|
||||
|
||||
/**
|
||||
* Rounds towards "nearest neighbor" unless both neighbors are equidistant, in which case round up.
|
||||
@@ -70,28 +61,28 @@ final class RoundingMode
|
||||
* Behaves as for UP if the discarded fraction is >= 0.5; otherwise, behaves as for DOWN.
|
||||
* Note that this is the rounding mode commonly taught at school.
|
||||
*/
|
||||
public const HALF_UP = 5;
|
||||
case HALF_UP;
|
||||
|
||||
/**
|
||||
* Rounds towards "nearest neighbor" unless both neighbors are equidistant, in which case round down.
|
||||
*
|
||||
* Behaves as for UP if the discarded fraction is > 0.5; otherwise, behaves as for DOWN.
|
||||
*/
|
||||
public const HALF_DOWN = 6;
|
||||
case HALF_DOWN;
|
||||
|
||||
/**
|
||||
* Rounds towards "nearest neighbor" unless both neighbors are equidistant, in which case round towards positive infinity.
|
||||
*
|
||||
* If the result is positive, behaves as for HALF_UP; if negative, behaves as for HALF_DOWN.
|
||||
*/
|
||||
public const HALF_CEILING = 7;
|
||||
case HALF_CEILING;
|
||||
|
||||
/**
|
||||
* Rounds towards "nearest neighbor" unless both neighbors are equidistant, in which case round towards negative infinity.
|
||||
*
|
||||
* If the result is positive, behaves as for HALF_DOWN; if negative, behaves as for HALF_UP.
|
||||
*/
|
||||
public const HALF_FLOOR = 8;
|
||||
case HALF_FLOOR;
|
||||
|
||||
/**
|
||||
* Rounds towards the "nearest neighbor" unless both neighbors are equidistant, in which case rounds towards the even neighbor.
|
||||
@@ -103,5 +94,5 @@ final class RoundingMode
|
||||
* cumulative error when applied repeatedly over a sequence of calculations.
|
||||
* It is sometimes known as "Banker's rounding", and is chiefly used in the USA.
|
||||
*/
|
||||
public const HALF_EVEN = 9;
|
||||
case HALF_EVEN;
|
||||
}
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
ko_fi: codemasher
|
||||
custom: "https://www.paypal.com/donate?hosted_button_id=WLYUNAT9ZTJZ4"
|
||||
@@ -1,82 +0,0 @@
|
||||
# https://help.github.com/en/categories/automating-your-workflow-with-github-actions
|
||||
# https://github.com/sebastianbergmann/phpunit/blob/master/.github/workflows/ci.yml
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- v4.3.x
|
||||
pull_request:
|
||||
branches:
|
||||
- v4.3.x
|
||||
|
||||
name: "Continuous Integration"
|
||||
|
||||
jobs:
|
||||
|
||||
static-code-analysis:
|
||||
name: "Static Code Analysis"
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
env:
|
||||
PHAN_ALLOW_XDEBUG: 0
|
||||
PHAN_DISABLE_XDEBUG_WARN: 1
|
||||
|
||||
steps:
|
||||
- name: "Checkout"
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: "Install PHP"
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: "7.4"
|
||||
coverage: none
|
||||
tools: pecl
|
||||
extensions: ast, gd, imagick, json, mbstring
|
||||
|
||||
- name: "Update dependencies with composer"
|
||||
run: composer update --no-interaction --no-ansi --no-progress --no-suggest
|
||||
|
||||
- name: "Run phan"
|
||||
run: php vendor/bin/phan
|
||||
|
||||
tests:
|
||||
name: "Unit Tests"
|
||||
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os:
|
||||
- ubuntu-latest
|
||||
- windows-latest
|
||||
php-version:
|
||||
- "7.4"
|
||||
- "8.0"
|
||||
- "8.1"
|
||||
|
||||
steps:
|
||||
# - name: "Configure git to avoid issues with line endings"
|
||||
# if: matrix.os == 'windows-latest'
|
||||
# run: git config --global core.autocrlf false
|
||||
|
||||
- name: "Checkout"
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: "Install PHP with extensions"
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: ${{ matrix.php-version }}
|
||||
coverage: pcov
|
||||
tools: pecl
|
||||
extensions: gd, imagick, json, mbstring
|
||||
|
||||
- name: "Install dependencies with composer"
|
||||
run: composer update --no-ansi --no-interaction --no-progress --no-suggest
|
||||
|
||||
- name: "Run tests with phpunit"
|
||||
run: php vendor/bin/phpunit --configuration=phpunit.xml
|
||||
|
||||
- name: "Send code coverage report to Codecov.io"
|
||||
uses: codecov/codecov-action@v3
|
||||
5
vendor/chillerlan/php-qrcode/.gitignore
vendored
5
vendor/chillerlan/php-qrcode/.gitignore
vendored
@@ -1,5 +0,0 @@
|
||||
.build/*
|
||||
.idea/*
|
||||
docs/*
|
||||
vendor/*
|
||||
composer.lock
|
||||
55
vendor/chillerlan/php-qrcode/.phan/config.php
vendored
55
vendor/chillerlan/php-qrcode/.phan/config.php
vendored
@@ -1,55 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* This configuration will be read and overlaid on top of the
|
||||
* default configuration. Command-line arguments will be applied
|
||||
* after this file is read.
|
||||
*/
|
||||
return [
|
||||
// Supported values: `'5.6'`, `'7.0'`, `'7.1'`, `'7.2'`, `'7.3'`,
|
||||
// `'7.4'`, `null`.
|
||||
// If this is set to `null`,
|
||||
// then Phan assumes the PHP version which is closest to the minor version
|
||||
// of the php executable used to execute Phan.
|
||||
//
|
||||
// Note that the **only** effect of choosing `'5.6'` is to infer
|
||||
// that functions removed in php 7.0 exist.
|
||||
// (See `backward_compatibility_checks` for additional options)
|
||||
'target_php_version' => '7.4',
|
||||
|
||||
// A list of directories that should be parsed for class and
|
||||
// method information. After excluding the directories
|
||||
// defined in exclude_analysis_directory_list, the remaining
|
||||
// files will be statically analyzed for errors.
|
||||
//
|
||||
// Thus, both first-party and third-party code being used by
|
||||
// your application should be included in this list.
|
||||
'directory_list' => [
|
||||
'examples',
|
||||
'src',
|
||||
'tests',
|
||||
'vendor',
|
||||
'.phan/stubs'
|
||||
],
|
||||
|
||||
// A regex used to match every file name that you want to
|
||||
// exclude from parsing. Actual value will exclude every
|
||||
// "test", "tests", "Test" and "Tests" folders found in
|
||||
// "vendor/" directory.
|
||||
'exclude_file_regex' => '@^vendor/.*/(tests?|Tests?)/@',
|
||||
|
||||
// A directory list that defines files that will be excluded
|
||||
// from static analysis, but whose class and method
|
||||
// information should be included.
|
||||
//
|
||||
// Generally, you'll want to include the directories for
|
||||
// third-party code (such as "vendor/") in this list.
|
||||
//
|
||||
// n.b.: If you'd like to parse but not analyze 3rd
|
||||
// party code, directories containing that code
|
||||
// should be added to both the `directory_list`
|
||||
// and `exclude_analysis_directory_list` arrays.
|
||||
'exclude_analysis_directory_list' => [
|
||||
'vendor/',
|
||||
'.phan/stubs'
|
||||
],
|
||||
];
|
||||
6744
vendor/chillerlan/php-qrcode/.phan/stubs/imagick.php
vendored
6744
vendor/chillerlan/php-qrcode/.phan/stubs/imagick.php
vendored
File diff suppressed because it is too large
Load Diff
16
vendor/chillerlan/php-qrcode/.scrutinizer.yml
vendored
16
vendor/chillerlan/php-qrcode/.scrutinizer.yml
vendored
@@ -1,16 +0,0 @@
|
||||
build:
|
||||
nodes:
|
||||
analysis:
|
||||
tests:
|
||||
override:
|
||||
- php-scrutinizer-run
|
||||
environment:
|
||||
php: 8.0.0
|
||||
|
||||
filter:
|
||||
excluded_paths:
|
||||
- examples/*
|
||||
- tests/*
|
||||
- vendor/*
|
||||
- .github/*
|
||||
- .phan/*
|
||||
239
vendor/chillerlan/php-qrcode/README.md
vendored
239
vendor/chillerlan/php-qrcode/README.md
vendored
@@ -7,26 +7,23 @@ namespaced, cleaned up, improved and other stuff.
|
||||
|
||||
[![PHP Version Support][php-badge]][php]
|
||||
[![Packagist version][packagist-badge]][packagist]
|
||||
[![License][license-badge]][license]
|
||||
[![CodeCov][coverage-badge]][coverage]
|
||||
[![Scrunitizer CI][scrutinizer-badge]][scrutinizer]
|
||||
[![Packagist downloads][downloads-badge]][downloads]<br/>
|
||||
[![Continuous Integration][gh-action-badge]][gh-action]
|
||||
[![CodeCov][coverage-badge]][coverage]
|
||||
[![Codacy][codacy-badge]][codacy]
|
||||
[![Packagist downloads][downloads-badge]][downloads]
|
||||
|
||||
[php-badge]: https://img.shields.io/packagist/php-v/chillerlan/php-qrcode?logo=php&color=8892BF
|
||||
[php]: https://www.php.net/supported-versions.php
|
||||
[packagist-badge]: https://img.shields.io/packagist/v/chillerlan/php-qrcode.svg?logo=packagist
|
||||
[packagist]: https://packagist.org/packages/chillerlan/php-qrcode
|
||||
[license-badge]: https://img.shields.io/github/license/chillerlan/php-qrcode.svg
|
||||
[license]: https://github.com/chillerlan/php-qrcode/blob/main/LICENSE
|
||||
[coverage-badge]: https://img.shields.io/codecov/c/github/chillerlan/php-qrcode.svg?logo=codecov
|
||||
[coverage]: https://codecov.io/github/chillerlan/php-qrcode
|
||||
[scrutinizer-badge]: https://img.shields.io/scrutinizer/g/chillerlan/php-qrcode.svg?logo=scrutinizer
|
||||
[scrutinizer]: https://scrutinizer-ci.com/g/chillerlan/php-qrcode
|
||||
[downloads-badge]: https://img.shields.io/packagist/dt/chillerlan/php-qrcode.svg?logo=packagist
|
||||
[coverage-badge]: https://img.shields.io/codecov/c/github/chillerlan/php-qrcode/v4.3.x?logo=codecov
|
||||
[coverage]: https://app.codecov.io/gh/chillerlan/php-qrcode/tree/v4.3.x
|
||||
[codacy-badge]: https://img.shields.io/codacy/grade/edccfc4fe5a34b74b1c53ee03f097b8d/v4.3.x?logo=codacy
|
||||
[codacy]: https://app.codacy.com/gh/chillerlan/php-qrcode/dashboard?branch=v4.3.x
|
||||
[downloads-badge]: https://img.shields.io/packagist/dt/chillerlan/php-qrcode?logo=packagist
|
||||
[downloads]: https://packagist.org/packages/chillerlan/php-qrcode/stats
|
||||
[gh-action-badge]: https://github.com/chillerlan/php-qrcode/workflows/Continuous%20Integration/badge.svg
|
||||
[gh-action]: https://github.com/chillerlan/php-qrcode/actions?query=workflow%3A%22Continuous+Integration%22+branch%3Av4.3.x
|
||||
[gh-action-badge]: https://img.shields.io/github/actions/workflow/status/chillerlan/php-qrcode/tests.yml?branch=v4.3.x&logo=github
|
||||
[gh-action]: https://github.com/chillerlan/php-qrcode/actions/workflows/tests.yml?query=branch%3Av4.3.x
|
||||
|
||||
# Documentation
|
||||
|
||||
@@ -48,7 +45,7 @@ via terminal: `composer require chillerlan/php-qrcode`
|
||||
{
|
||||
"require": {
|
||||
"php": "^7.4 || ^8.0",
|
||||
"chillerlan/php-qrcode": "v4.3.x-dev"
|
||||
"chillerlan/php-qrcode": "v4.3.x-dev#<commit_hash>"
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -62,7 +59,7 @@ For PHP version ...
|
||||
|
||||
In case you want to keep using `v4.3.x-dev`, specify the hash of a commit to avoid running into unforseen issues like so: `v4.3.x-dev#c115f7bc51d466ccb24c544e88329804aad8c2a0`
|
||||
|
||||
PSA: [PHP 7.0 - 7.3 are EOL](https://www.php.net/supported-versions.php) and therefore the respective `QRCode` versions are also no longer supported!
|
||||
PSA: [PHP 7.0 - 7.4 are EOL](https://www.php.net/supported-versions.php) and therefore the respective `QRCode` versions are also no longer supported!
|
||||
|
||||
## Quickstart
|
||||
We want to encode this URI for a mobile authenticator into a QRcode image:
|
||||
@@ -252,40 +249,41 @@ $options = new QROptions;
|
||||
// for HTML, SVG and ImageMagick
|
||||
$options->moduleValues = [
|
||||
// finder
|
||||
1536 => '#A71111', // dark (true)
|
||||
6 => '#FFBFBF', // light (false)
|
||||
QRMatrix::M_FINDER_DARK => '#A71111', // dark (true)
|
||||
QRMatrix::M_FINDER_DOT_DARK => '#A71111', // dark (true)
|
||||
QRMatrix::M_FINDER => '#FFBFBF', // light (false)
|
||||
// alignment
|
||||
2560 => '#A70364',
|
||||
10 => '#FFC9C9',
|
||||
QRMatrix::M_ALIGNMENT_DARK => '#A70364',
|
||||
QRMatrix::M_ALIGNMENT => '#FFC9C9',
|
||||
// timing
|
||||
3072 => '#98005D',
|
||||
12 => '#FFB8E9',
|
||||
QRMatrix::M_TIMING_DARK => '#98005D',
|
||||
QRMatrix::M_TIMING => '#FFB8E9',
|
||||
// format
|
||||
3584 => '#003804',
|
||||
14 => '#00FB12',
|
||||
QRMatrix::M_FORMAT_DARK => '#003804',
|
||||
QRMatrix::M_FORMAT => '#00FB12',
|
||||
// version
|
||||
4096 => '#650098',
|
||||
16 => '#E0B8FF',
|
||||
QRMatrix::M_VERSION_DARK => '#650098',
|
||||
QRMatrix::M_VERSION => '#E0B8FF',
|
||||
// data
|
||||
1024 => '#4A6000',
|
||||
4 => '#ECF9BE',
|
||||
QRMatrix::M_DATA_DARK => '#4A6000',
|
||||
QRMatrix::M_DATA => '#ECF9BE',
|
||||
// darkmodule
|
||||
512 => '#080063',
|
||||
QRMatrix::M_DARKMODULE_DARK => '#080063',
|
||||
// separator
|
||||
8 => '#AFBFBF',
|
||||
QRMatrix::M_SEPARATOR => '#AFBFBF',
|
||||
// quietzone
|
||||
18 => '#FFFFFF',
|
||||
QRMatrix::M_QUIETZONE => '#FFFFFF',
|
||||
];
|
||||
|
||||
// for the image output types
|
||||
$options->moduleValues = [
|
||||
512 => [0, 0, 0],
|
||||
QRMatrix::M_DATA_DARK => [0, 0, 0],
|
||||
// ...
|
||||
];
|
||||
|
||||
// for string/text output
|
||||
$options->moduleValues = [
|
||||
512 => '#',
|
||||
QRMatrix::M_DATA_DARK => '#',
|
||||
// ...
|
||||
];
|
||||
```
|
||||
@@ -294,106 +292,115 @@ $options->moduleValues = [
|
||||
## Public API
|
||||
|
||||
### `QRCode` API
|
||||
#### Methods
|
||||
method | return | description
|
||||
------ | ------ | -----------
|
||||
`__construct(QROptions $options = null)` | - | see [`SettingsContainerInterface`](https://github.com/chillerlan/php-settings-container/blob/main/src/SettingsContainerInterface.php)
|
||||
`render(string $data, string $file = null)` | mixed, `QROutputInterface::dump()` | renders a QR Code for the given `$data` and `QROptions`, saves `$file` optional
|
||||
`getMatrix(string $data)` | `QRMatrix` | returns a `QRMatrix` object for the given `$data` and current `QROptions`
|
||||
`initDataInterface(string $data)` | `QRDataInterface` | returns a fresh `QRDataInterface` for the given `$data`
|
||||
`isNumber(string $string)` | bool | checks if a string qualifies for `Number`
|
||||
`isAlphaNum(string $string)` | bool | checks if a string qualifies for `AlphaNum`
|
||||
`isKanji(string $string)` | bool | checks if a string qualifies for `Kanji`
|
||||
`isByte(string $string)` | bool | checks if a string is non-empty
|
||||
|
||||
#### Constants
|
||||
name | description
|
||||
---- | -----------
|
||||
`VERSION_AUTO` | `QROptions::$version`
|
||||
`MASK_PATTERN_AUTO` | `QROptions::$maskPattern`
|
||||
`OUTPUT_MARKUP_SVG`, `OUTPUT_MARKUP_HTML` | `QROptions::$outputType` markup
|
||||
`OUTPUT_IMAGE_PNG`, `OUTPUT_IMAGE_JPG`, `OUTPUT_IMAGE_GIF` | `QROptions::$outputType` image
|
||||
`OUTPUT_STRING_JSON`, `OUTPUT_STRING_TEXT` | `QROptions::$outputType` string
|
||||
`OUTPUT_IMAGICK` | `QROptions::$outputType` ImageMagick
|
||||
`OUTPUT_FPDF` | `QROptions::$outputType` PDF, using [FPDF](https://github.com/setasign/fpdf)
|
||||
`OUTPUT_CUSTOM` | `QROptions::$outputType`, requires `QROptions::$outputInterface`
|
||||
`ECC_L`, `ECC_M`, `ECC_Q`, `ECC_H`, | ECC-Level: 7%, 15%, 25%, 30% in `QROptions::$eccLevel`
|
||||
`DATA_NUMBER`, `DATA_ALPHANUM`, `DATA_BYTE`, `DATA_KANJI` | `QRDataInterface::$datamode`
|
||||
#### Methods
|
||||
| method | return | description |
|
||||
|---------------------------------------------|------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| `__construct(QROptions $options = null)` | - | see [`SettingsContainerInterface`](https://github.com/chillerlan/php-settings-container/blob/main/src/SettingsContainerInterface.php) |
|
||||
| `render(string $data, string $file = null)` | mixed, `QROutputInterface::dump()` | renders a QR Code for the given `$data` and `QROptions`, saves `$file` optional |
|
||||
| `getMatrix(string $data)` | `QRMatrix` | returns a `QRMatrix` object for the given `$data` and current `QROptions` |
|
||||
| `initDataInterface(string $data)` | `QRDataInterface` | returns a fresh `QRDataInterface` for the given `$data` |
|
||||
| `isNumber(string $string)` | bool | checks if a string qualifies for `Number` |
|
||||
| `isAlphaNum(string $string)` | bool | checks if a string qualifies for `AlphaNum` |
|
||||
| `isKanji(string $string)` | bool | checks if a string qualifies for `Kanji` |
|
||||
| `isByte(string $string)` | bool | checks if a string is non-empty |
|
||||
|
||||
#### Constants
|
||||
| name | description |
|
||||
|------------------------------------------------------------|------------------------------------------------------------------------------|
|
||||
| `VERSION_AUTO` | `QROptions::$version` |
|
||||
| `MASK_PATTERN_AUTO` | `QROptions::$maskPattern` |
|
||||
| `OUTPUT_MARKUP_SVG`, `OUTPUT_MARKUP_HTML` | `QROptions::$outputType` markup |
|
||||
| `OUTPUT_IMAGE_PNG`, `OUTPUT_IMAGE_JPG`, `OUTPUT_IMAGE_GIF` | `QROptions::$outputType` image |
|
||||
| `OUTPUT_STRING_JSON`, `OUTPUT_STRING_TEXT` | `QROptions::$outputType` string |
|
||||
| `OUTPUT_IMAGICK` | `QROptions::$outputType` ImageMagick |
|
||||
| `OUTPUT_FPDF` | `QROptions::$outputType` PDF, using [FPDF](https://github.com/setasign/fpdf) |
|
||||
| `OUTPUT_CUSTOM` | `QROptions::$outputType`, requires `QROptions::$outputInterface` |
|
||||
| `ECC_L`, `ECC_M`, `ECC_Q`, `ECC_H`, | ECC-Level: 7%, 15%, 25%, 30% in `QROptions::$eccLevel` |
|
||||
| `DATA_NUMBER`, `DATA_ALPHANUM`, `DATA_BYTE`, `DATA_KANJI` | `QRDataInterface::$datamode` |
|
||||
|
||||
### `QRMatrix` API
|
||||
|
||||
#### Methods
|
||||
method | return | description
|
||||
------ | ------ | -----------
|
||||
`__construct(int $version, int $eclevel)` | - | -
|
||||
`init(int $maskPattern, bool $test = null)` | `QRMatrix` |
|
||||
`matrix()` | array | the internal matrix representation as a 2 dimensional array
|
||||
`version()` | int | the current QR Code version
|
||||
`eccLevel()` | int | current ECC level
|
||||
`maskPattern()` | int | the used mask pattern
|
||||
`size()` | int | the absoulute size of the matrix, including quiet zone (if set). `$version * 4 + 17 + 2 * $quietzone`
|
||||
`get(int $x, int $y)` | int | returns the value of the module
|
||||
`set(int $x, int $y, bool $value, int $M_TYPE)` | `QRMatrix` | sets the `$M_TYPE` value for the module
|
||||
`check(int $x, int $y)` | bool | checks whether a module is true (dark) or false (light)
|
||||
| method | return | description |
|
||||
|-------------------------------------------------|------------|-------------------------------------------------------------------------------------------------------|
|
||||
| `__construct(int $version, int $eclevel)` | - | - |
|
||||
| `init(int $maskPattern, bool $test = null)` | `QRMatrix` | |
|
||||
| `matrix()` | array | the internal matrix representation as a 2 dimensional array |
|
||||
| `version()` | int | the current QR Code version |
|
||||
| `eccLevel()` | int | current ECC level |
|
||||
| `maskPattern()` | int | the used mask pattern |
|
||||
| `size()` | int | the absoulute size of the matrix, including quiet zone (if set). `$version * 4 + 17 + 2 * $quietzone` |
|
||||
| `get(int $x, int $y)` | int | returns the value of the module |
|
||||
| `set(int $x, int $y, bool $value, int $M_TYPE)` | `QRMatrix` | sets the `$M_TYPE` value for the module |
|
||||
| `check(int $x, int $y)` | bool | checks whether a module is true (dark) or false (light) |
|
||||
|
||||
#### Constants
|
||||
name | light (false) | dark (true) | description
|
||||
---- | ------------- | ----------- | -----------
|
||||
`M_NULL` | 0 | - | module not set (should never appear. if so, there's an error)
|
||||
`M_DARKMODULE` | - | 512 | once per matrix at `$xy = [8, 4 * $version + 9]`
|
||||
`M_DATA` | 4 | 1024 | the actual encoded data
|
||||
`M_FINDER` | 6 | 1536 | the 7x7 finder patterns
|
||||
`M_SEPARATOR` | 8 | - | separator lines around the finder patterns
|
||||
`M_ALIGNMENT` | 10 | 2560 | the 5x5 alignment patterns
|
||||
`M_TIMING` | 12 | 3072 | the timing pattern lines
|
||||
`M_FORMAT` | 14 | 3584 | format information pattern
|
||||
`M_VERSION` | 16 | 4096 | version information pattern
|
||||
`M_QUIETZONE` | 18 | - | margin around the QR Code
|
||||
`M_LOGO` | 20 | - | space for a logo image (not used yet)
|
||||
`M_TEST` | 255 | 65280 | test value
|
||||
| name | description |
|
||||
|----------------------|---------------------------------------------------------------|
|
||||
| `M_NULL` | module not set (should never appear. if so, there's an error) |
|
||||
| `M_DARKMODULE` | once per matrix at `$xy = [8, 4 * $version + 9]` |
|
||||
| `M_DARKMODULE_LIGHT` | (reserved for reflectance reversal) |
|
||||
| `M_DATA` | the actual encoded data |
|
||||
| `M_DATA_DARK` | |
|
||||
| `M_FINDER` | the 7x7 finder patterns |
|
||||
| `M_FINDER_DARK` | |
|
||||
| `M_FINDER_DOT` | the 3x3 dot inside the finder patterns |
|
||||
| `M_FINDER_DOT_LIGHT` | (reserved for reflectance reversal) |
|
||||
| `M_SEPARATOR` | separator lines around the finder patterns |
|
||||
| `M_SEPARATOR_DARK` | (reserved for reflectance reversal) |
|
||||
| `M_ALIGNMENT` | the 5x5 alignment patterns |
|
||||
| `M_ALIGNMENT_DARK` | |
|
||||
| `M_TIMING` | the timing pattern lines |
|
||||
| `M_TIMING_DARK` | |
|
||||
| `M_FORMAT` | format information pattern |
|
||||
| `M_FORMAT_DARK` | |
|
||||
| `M_VERSION` | version information pattern |
|
||||
| `M_VERSION_DARK` | |
|
||||
| `M_QUIETZONE` | margin around the QR Code |
|
||||
| `M_QUIETZONE_DARK` | (reserved for reflectance reversal) |
|
||||
| `M_LOGO` | space for a logo image |
|
||||
| `M_LOGO_DARK` | (reserved for reflectance reversal) |
|
||||
|
||||
### `QROptions` API
|
||||
|
||||
#### Properties
|
||||
property | type | default | allowed | description
|
||||
-------- | ---- | ------- | ------- | -----------
|
||||
`$version` | int | `QRCode::VERSION_AUTO` | 1...40 | the [QR Code version number](http://www.qrcode.com/en/about/version.html)
|
||||
`$versionMin` | int | 1 | 1...40 | Minimum QR version (if `$version = QRCode::VERSION_AUTO`)
|
||||
`$versionMax` | int | 40 | 1...40 | Maximum QR version (if `$version = QRCode::VERSION_AUTO`)
|
||||
`$eccLevel` | int | `QRCode::ECC_L` | `QRCode::ECC_X` | Error correct level, where X = L (7%), M (15%), Q (25%), H (30%)
|
||||
`$maskPattern` | int | `QRCode::MASK_PATTERN_AUTO` | 0...7 | Mask Pattern to use
|
||||
`$addQuietzone` | bool | `true` | - | Add a "quiet zone" (margin) according to the QR code spec
|
||||
`$quietzoneSize` | int | 4 | clamped to 0 ... `$matrixSize / 2` | Size of the quiet zone
|
||||
`$dataModeOverride` | string | `null` | `Number`, `AlphaNum`, `Kanji`, `Byte` | allows overriding the data type detection
|
||||
`$outputType` | string | `QRCode::OUTPUT_IMAGE_PNG` | `QRCode::OUTPUT_*` | built-in output type
|
||||
`$outputInterface` | string | `null` | * | FQCN of the custom `QROutputInterface` if `QROptions::$outputType` is set to `QRCode::OUTPUT_CUSTOM`
|
||||
`$cachefile` | string | `null` | * | optional cache file path
|
||||
`$eol` | string | `PHP_EOL` | * | newline string (HTML, SVG, TEXT)
|
||||
`$scale` | int | 5 | * | size of a QR code pixel (SVG, IMAGE_*), HTML -> via CSS
|
||||
`$cssClass` | string | `null` | * | a common css class
|
||||
`$svgOpacity` | float | 1.0 | 0...1 |
|
||||
`$svgDefs` | string | * | * | anything between [`<defs>`](https://developer.mozilla.org/docs/Web/SVG/Element/defs)
|
||||
`$svgViewBoxSize` | int | `null` | * | a positive integer which defines width/height of the [viewBox attribute](https://css-tricks.com/scale-svg/#article-header-id-3)
|
||||
`$textDark` | string | '🔴' | * | string substitute for dark
|
||||
`$textLight` | string | '⭕' | * | string substitute for light
|
||||
`$markupDark` | string | '#000' | * | markup substitute for dark (CSS value)
|
||||
`$markupLight` | string | '#fff' | * | markup substitute for light (CSS value)
|
||||
`$imageBase64` | bool | `true` | - | whether to return the image data as base64 or raw like from `file_get_contents()`
|
||||
`$imageTransparent` | bool | `true` | - | toggle transparency (no jpeg support)
|
||||
`$imageTransparencyBG` | array | `[255, 255, 255]` | `[R, G, B]` | the RGB values for the transparent color, see [`imagecolortransparent()`](http://php.net/manual/function.imagecolortransparent.php)
|
||||
`$pngCompression` | int | -1 | -1 ... 9 | `imagepng()` compression level, -1 = auto
|
||||
`$jpegQuality` | int | 85 | 0 - 100 | `imagejpeg()` quality
|
||||
`$imagickFormat` | string | 'png' | * | ImageMagick output type, see `Imagick::setType()`
|
||||
`$imagickBG` | string | `null` | * | ImageMagick background color, see `ImagickPixel::__construct()`
|
||||
`$moduleValues` | array | `null` | * | Module values map, see [[Custom output interface]] and `QROutputInterface::DEFAULT_MODULE_VALUES`
|
||||
|
||||
| property | type | default | allowed | description |
|
||||
|------------------------|--------|-----------------------------|---------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| `$version` | int | `QRCode::VERSION_AUTO` | 1...40 | the [QR Code version number](http://www.qrcode.com/en/about/version.html) |
|
||||
| `$versionMin` | int | 1 | 1...40 | Minimum QR version (if `$version = QRCode::VERSION_AUTO`) |
|
||||
| `$versionMax` | int | 40 | 1...40 | Maximum QR version (if `$version = QRCode::VERSION_AUTO`) |
|
||||
| `$eccLevel` | int | `QRCode::ECC_L` | `QRCode::ECC_X` | Error correct level, where X = L (7%), M (15%), Q (25%), H (30%) |
|
||||
| `$maskPattern` | int | `QRCode::MASK_PATTERN_AUTO` | 0...7 | Mask Pattern to use |
|
||||
| `$addQuietzone` | bool | `true` | - | Add a "quiet zone" (margin) according to the QR code spec |
|
||||
| `$quietzoneSize` | int | 4 | clamped to 0 ... `$matrixSize / 2` | Size of the quiet zone |
|
||||
| `$dataModeOverride` | string | `null` | `Number`, `AlphaNum`, `Kanji`, `Byte` | allows overriding the data type detection |
|
||||
| `$outputType` | string | `QRCode::OUTPUT_IMAGE_PNG` | `QRCode::OUTPUT_*` | built-in output type |
|
||||
| `$outputInterface` | string | `null` | * | FQCN of the custom `QROutputInterface` if `QROptions::$outputType` is set to `QRCode::OUTPUT_CUSTOM` |
|
||||
| `$cachefile` | string | `null` | * | optional cache file path |
|
||||
| `$eol` | string | `PHP_EOL` | * | newline string (HTML, SVG, TEXT) |
|
||||
| `$scale` | int | 5 | * | size of a QR code pixel (SVG, IMAGE_*), HTML -> via CSS |
|
||||
| `$cssClass` | string | `null` | * | a common css class |
|
||||
| `$svgOpacity` | float | 1.0 | 0...1 | |
|
||||
| `$svgDefs` | string | * | * | anything between [`<defs>`](https://developer.mozilla.org/docs/Web/SVG/Element/defs) |
|
||||
| `$svgViewBoxSize` | int | `null` | * | a positive integer which defines width/height of the [viewBox attribute](https://css-tricks.com/scale-svg/#article-header-id-3) |
|
||||
| `$textDark` | string | '██' | * | string substitute for dark |
|
||||
| `$textLight` | string | '░░' | * | string substitute for light |
|
||||
| `$markupDark` | string | '#000' | * | markup substitute for dark (CSS value) |
|
||||
| `$markupLight` | string | '#fff' | * | markup substitute for light (CSS value) |
|
||||
| `$imageBase64` | bool | `true` | - | whether to return the image data as base64 or raw like from `file_get_contents()` |
|
||||
| `$imageTransparent` | bool | `true` | - | toggle transparency (no jpeg support) |
|
||||
| `$imageTransparencyBG` | array | `[255, 255, 255]` | `[R, G, B]` | the RGB values for the transparent color, see [`imagecolortransparent()`](http://php.net/manual/function.imagecolortransparent.php) |
|
||||
| `$pngCompression` | int | -1 | -1 ... 9 | `imagepng()` compression level, -1 = auto |
|
||||
| `$jpegQuality` | int | 85 | 0 - 100 | `imagejpeg()` quality |
|
||||
| `$imagickFormat` | string | 'png' | * | ImageMagick output type, see `Imagick::setType()` |
|
||||
| `$imagickBG` | string | `null` | * | ImageMagick background color, see `ImagickPixel::__construct()` |
|
||||
| `$moduleValues` | array | `null` | * | Module values map, see [[Custom output interface]] and `QROutputInterface::DEFAULT_MODULE_VALUES` |
|
||||
|
||||
## Framework Integration
|
||||
- Drupal:
|
||||
- [Google Authenticator Login `ga_login`](https://www.drupal.org/project/ga_login)
|
||||
- Symfony
|
||||
- [phpqrcode-bundle](https://github.com/jonasarts/phpqrcode-bundle)
|
||||
- [phpqrcode-bundle](https://github.com/jonasarts/phpqrcode-bundle)
|
||||
- WordPress:
|
||||
- [`wp-two-factor-auth`](https://github.com/sjinks/wp-two-factor-auth)
|
||||
- [`simple-2fa`](https://wordpress.org/plugins/simple-2fa/)
|
||||
|
||||
19
vendor/chillerlan/php-qrcode/composer.json
vendored
19
vendor/chillerlan/php-qrcode/composer.json
vendored
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "chillerlan/php-qrcode",
|
||||
"description": "A QR code generator. PHP 7.4+",
|
||||
"description": "A QR code generator with a user friendly API. PHP 7.4+",
|
||||
"homepage": "https://github.com/chillerlan/php-qrcode",
|
||||
"license": "MIT",
|
||||
"minimum-stability": "stable",
|
||||
@@ -26,16 +26,19 @@
|
||||
"require": {
|
||||
"php": "^7.4 || ^8.0",
|
||||
"ext-mbstring": "*",
|
||||
"chillerlan/php-settings-container": "^2.1.4"
|
||||
"chillerlan/php-settings-container": "^2.1.6 || ^3.2.1"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^9.5",
|
||||
"phan/phan": "^5.3",
|
||||
"setasign/fpdf": "^1.8.2"
|
||||
"phan/phan": "^5.4.5",
|
||||
"phpmd/phpmd": "^2.15",
|
||||
"phpunit/phpunit": "^9.6",
|
||||
"setasign/fpdf": "^1.8.2",
|
||||
"squizlabs/php_codesniffer": "^3.11"
|
||||
},
|
||||
"suggest": {
|
||||
"chillerlan/php-authenticator": "Yet another Google authenticator! Also creates URIs for mobile apps.",
|
||||
"setasign/fpdf": "Required to use the QR FPDF output."
|
||||
"setasign/fpdf": "Required to use the QR FPDF output.",
|
||||
"simple-icons/simple-icons": "SVG icons that you can use to embed as logos in the QR Code"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
@@ -44,9 +47,7 @@
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
"chillerlan\\QRCodePublic\\": "public/",
|
||||
"chillerlan\\QRCodeTest\\": "tests/",
|
||||
"chillerlan\\QRCodeExamples\\": "examples/"
|
||||
"chillerlan\\QRCodeTest\\": "tests/"
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Class MyCustomOutput
|
||||
*
|
||||
* @filesource MyCustomOutput.php
|
||||
* @created 24.12.2017
|
||||
* @package chillerlan\QRCodeExamples
|
||||
* @author Smiley <smiley@chillerlan.net>
|
||||
* @copyright 2017 Smiley
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
namespace chillerlan\QRCodeExamples;
|
||||
|
||||
use chillerlan\QRCode\Output\QROutputAbstract;
|
||||
|
||||
class MyCustomOutput extends QROutputAbstract{
|
||||
|
||||
protected function setModuleValues():void{
|
||||
// TODO: Implement setModuleValues() method.
|
||||
}
|
||||
|
||||
public function dump(string $file = null){
|
||||
|
||||
$output = '';
|
||||
|
||||
for($row = 0; $row < $this->moduleCount; $row++){
|
||||
for($col = 0; $col < $this->moduleCount; $col++){
|
||||
$output .= (int)$this->matrix->check($col, $row);
|
||||
}
|
||||
|
||||
$output .= \PHP_EOL;
|
||||
}
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,81 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Class QRImageWithLogo
|
||||
*
|
||||
* @filesource QRImageWithLogo.php
|
||||
* @created 18.11.2020
|
||||
* @package chillerlan\QRCodeExamples
|
||||
* @author smiley <smiley@chillerlan.net>
|
||||
* @copyright 2020 smiley
|
||||
* @license MIT
|
||||
*
|
||||
* @noinspection PhpComposerExtensionStubsInspection
|
||||
*/
|
||||
|
||||
namespace chillerlan\QRCodeExamples;
|
||||
|
||||
use chillerlan\QRCode\Output\{QRCodeOutputException, QRImage};
|
||||
|
||||
use function imagecopyresampled, imagecreatefrompng, imagesx, imagesy, is_file, is_readable;
|
||||
|
||||
/**
|
||||
* @property \chillerlan\QRCodeExamples\LogoOptions $options
|
||||
*/
|
||||
class QRImageWithLogo extends QRImage{
|
||||
|
||||
/**
|
||||
* @param string|null $file
|
||||
* @param string|null $logo
|
||||
*
|
||||
* @return string
|
||||
* @throws \chillerlan\QRCode\Output\QRCodeOutputException
|
||||
*/
|
||||
public function dump(string $file = null, string $logo = null):string{
|
||||
// set returnResource to true to skip further processing for now
|
||||
$this->options->returnResource = true;
|
||||
|
||||
// of course you could accept other formats too (such as resource or Imagick)
|
||||
// i'm not checking for the file type either for simplicity reasons (assuming PNG)
|
||||
if(!is_file($logo) || !is_readable($logo)){
|
||||
throw new QRCodeOutputException('invalid logo');
|
||||
}
|
||||
|
||||
$this->matrix->setLogoSpace(
|
||||
$this->options->logoSpaceWidth,
|
||||
$this->options->logoSpaceHeight
|
||||
// not utilizing the position here
|
||||
);
|
||||
|
||||
// there's no need to save the result of dump() into $this->image here
|
||||
parent::dump($file);
|
||||
|
||||
$im = imagecreatefrompng($logo);
|
||||
|
||||
// get logo image size
|
||||
$w = imagesx($im);
|
||||
$h = imagesy($im);
|
||||
|
||||
// set new logo size, leave a border of 1 module (no proportional resize/centering)
|
||||
$lw = ($this->options->logoSpaceWidth - 2) * $this->options->scale;
|
||||
$lh = ($this->options->logoSpaceHeight - 2) * $this->options->scale;
|
||||
|
||||
// get the qrcode size
|
||||
$ql = $this->matrix->size() * $this->options->scale;
|
||||
|
||||
// scale the logo and copy it over. done!
|
||||
imagecopyresampled($this->image, $im, ($ql - $lw) / 2, ($ql - $lh) / 2, 0, 0, $lw, $lh, $w, $h);
|
||||
|
||||
$imageData = $this->dumpImage();
|
||||
|
||||
if($file !== null){
|
||||
$this->saveToFile($imageData, $file);
|
||||
}
|
||||
|
||||
if($this->options->imageBase64){
|
||||
$imageData = 'data:image/'.$this->options->outputType.';base64,'.base64_encode($imageData);
|
||||
}
|
||||
|
||||
return $imageData;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,100 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Class QRImageWithText
|
||||
*
|
||||
* example for additional text
|
||||
*
|
||||
* @link https://github.com/chillerlan/php-qrcode/issues/35
|
||||
*
|
||||
* @filesource QRImageWithText.php
|
||||
* @created 22.06.2019
|
||||
* @package chillerlan\QRCodeExamples
|
||||
* @author smiley <smiley@chillerlan.net>
|
||||
* @copyright 2019 smiley
|
||||
* @license MIT
|
||||
*
|
||||
* @noinspection PhpComposerExtensionStubsInspection
|
||||
*/
|
||||
|
||||
namespace chillerlan\QRCodeExamples;
|
||||
|
||||
use chillerlan\QRCode\Output\QRImage;
|
||||
|
||||
use function base64_encode, imagechar, imagecolorallocate, imagecolortransparent, imagecopymerge, imagecreatetruecolor,
|
||||
imagedestroy, imagefilledrectangle, imagefontwidth, in_array, round, str_split, strlen;
|
||||
|
||||
class QRImageWithText extends QRImage{
|
||||
|
||||
/**
|
||||
* @param string|null $file
|
||||
* @param string|null $text
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function dump(string $file = null, string $text = null):string{
|
||||
// set returnResource to true to skip further processing for now
|
||||
$this->options->returnResource = true;
|
||||
|
||||
// there's no need to save the result of dump() into $this->image here
|
||||
parent::dump($file);
|
||||
|
||||
// render text output if a string is given
|
||||
if($text !== null){
|
||||
$this->addText($text);
|
||||
}
|
||||
|
||||
$imageData = $this->dumpImage();
|
||||
|
||||
if($file !== null){
|
||||
$this->saveToFile($imageData, $file);
|
||||
}
|
||||
|
||||
if($this->options->imageBase64){
|
||||
$imageData = 'data:image/'.$this->options->outputType.';base64,'.base64_encode($imageData);
|
||||
}
|
||||
|
||||
return $imageData;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $text
|
||||
*/
|
||||
protected function addText(string $text):void{
|
||||
// save the qrcode image
|
||||
$qrcode = $this->image;
|
||||
|
||||
// options things
|
||||
$textSize = 3; // see imagefontheight() and imagefontwidth()
|
||||
$textBG = [200, 200, 200];
|
||||
$textColor = [50, 50, 50];
|
||||
|
||||
$bgWidth = $this->length;
|
||||
$bgHeight = $bgWidth + 20; // 20px extra space
|
||||
|
||||
// create a new image with additional space
|
||||
$this->image = imagecreatetruecolor($bgWidth, $bgHeight);
|
||||
$background = imagecolorallocate($this->image, ...$textBG);
|
||||
|
||||
// allow transparency
|
||||
if($this->options->imageTransparent && in_array($this->options->outputType, $this::TRANSPARENCY_TYPES, true)){
|
||||
imagecolortransparent($this->image, $background);
|
||||
}
|
||||
|
||||
// fill the background
|
||||
imagefilledrectangle($this->image, 0, 0, $bgWidth, $bgHeight, $background);
|
||||
|
||||
// copy over the qrcode
|
||||
imagecopymerge($this->image, $qrcode, 0, 0, 0, 0, $this->length, $this->length, 100);
|
||||
imagedestroy($qrcode);
|
||||
|
||||
$fontColor = imagecolorallocate($this->image, ...$textColor);
|
||||
$w = imagefontwidth($textSize);
|
||||
$x = round(($bgWidth - strlen($text) * $w) / 2);
|
||||
|
||||
// loop through the string and draw the letters
|
||||
foreach(str_split($text) as $i => $chr){
|
||||
imagechar($this->image, $textSize, (int)($i * $w + $x), $this->length, $chr, $fontColor);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* @filesource custom_output.php
|
||||
* @created 24.12.2017
|
||||
* @author Smiley <smiley@chillerlan.net>
|
||||
* @copyright 2017 Smiley
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
namespace chillerlan\QRCodeExamples;
|
||||
|
||||
use chillerlan\QRCode\{QRCode, QROptions};
|
||||
|
||||
require_once __DIR__.'/../vendor/autoload.php';
|
||||
|
||||
$data = 'https://www.youtube.com/watch?v=DLzxrzFCyOs&t=43s';
|
||||
|
||||
// invoke the QROutputInterface manually
|
||||
$options = new QROptions([
|
||||
'version' => 5,
|
||||
'eccLevel' => QRCode::ECC_L,
|
||||
]);
|
||||
|
||||
$qrOutputInterface = new MyCustomOutput($options, (new QRCode($options))->getMatrix($data));
|
||||
|
||||
var_dump($qrOutputInterface->dump());
|
||||
|
||||
|
||||
// or just
|
||||
$options = new QROptions([
|
||||
'version' => 5,
|
||||
'eccLevel' => QRCode::ECC_L,
|
||||
'outputType' => QRCode::OUTPUT_CUSTOM,
|
||||
'outputInterface' => MyCustomOutput::class,
|
||||
]);
|
||||
|
||||
var_dump((new QRCode($options))->render($data));
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 2.2 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 16 KiB |
47
vendor/chillerlan/php-qrcode/examples/fpdf.php
vendored
47
vendor/chillerlan/php-qrcode/examples/fpdf.php
vendored
@@ -1,47 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace chillerlan\QRCodeExamples;
|
||||
|
||||
use chillerlan\QRCode\{QRCode, QROptions};
|
||||
|
||||
require_once __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
$data = 'https://www.youtube.com/watch?v=DLzxrzFCyOs&t=43s';
|
||||
|
||||
$options = new QROptions([
|
||||
'version' => 7,
|
||||
'outputType' => QRCode::OUTPUT_FPDF,
|
||||
'eccLevel' => QRCode::ECC_L,
|
||||
'scale' => 5,
|
||||
'imageBase64' => false,
|
||||
'moduleValues' => [
|
||||
// finder
|
||||
1536 => [0, 63, 255], // dark (true)
|
||||
6 => [255, 255, 255], // light (false), white is the transparency color and is enabled by default
|
||||
// alignment
|
||||
2560 => [255, 0, 255],
|
||||
10 => [255, 255, 255],
|
||||
// timing
|
||||
3072 => [255, 0, 0],
|
||||
12 => [255, 255, 255],
|
||||
// format
|
||||
3584 => [67, 191, 84],
|
||||
14 => [255, 255, 255],
|
||||
// version
|
||||
4096 => [62, 174, 190],
|
||||
16 => [255, 255, 255],
|
||||
// data
|
||||
1024 => [0, 0, 0],
|
||||
4 => [255, 255, 255],
|
||||
// darkmodule
|
||||
512 => [0, 0, 0],
|
||||
// separator
|
||||
8 => [255, 255, 255],
|
||||
// quietzone
|
||||
18 => [255, 255, 255],
|
||||
],
|
||||
]);
|
||||
|
||||
\header('Content-type: application/pdf');
|
||||
|
||||
echo (new QRCode($options))->render($data);
|
||||
102
vendor/chillerlan/php-qrcode/examples/html.php
vendored
102
vendor/chillerlan/php-qrcode/examples/html.php
vendored
@@ -1,102 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* @filesource html.php
|
||||
* @created 21.12.2017
|
||||
* @author Smiley <smiley@chillerlan.net>
|
||||
* @copyright 2017 Smiley
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
namespace chillerlan\QRCodeExamples;
|
||||
|
||||
use chillerlan\QRCode\{QRCode, QROptions};
|
||||
|
||||
require_once '../vendor/autoload.php';
|
||||
|
||||
header('Content-Type: text/html; charset=utf-8');
|
||||
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
||||
<title>QRCode test</title>
|
||||
<style>
|
||||
body{
|
||||
margin: 5em;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
div.qrcode{
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
/* rows */
|
||||
div.qrcode > div {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
height: 10px;
|
||||
}
|
||||
|
||||
/* modules */
|
||||
div.qrcode > div > span {
|
||||
display: inline-block;
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
}
|
||||
|
||||
div.qrcode > div > span {
|
||||
background-color: #ccc;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="qrcode">
|
||||
<?php
|
||||
|
||||
$data = 'https://www.youtube.com/watch?v=DLzxrzFCyOs&t=43s';
|
||||
|
||||
$options = new QROptions([
|
||||
'version' => 5,
|
||||
'outputType' => QRCode::OUTPUT_MARKUP_HTML,
|
||||
'eccLevel' => QRCode::ECC_L,
|
||||
'moduleValues' => [
|
||||
// finder
|
||||
1536 => '#A71111', // dark (true)
|
||||
6 => '#FFBFBF', // light (false)
|
||||
// alignment
|
||||
2560 => '#A70364',
|
||||
10 => '#FFC9C9',
|
||||
// timing
|
||||
3072 => '#98005D',
|
||||
12 => '#FFB8E9',
|
||||
// format
|
||||
3584 => '#003804',
|
||||
14 => '#00FB12',
|
||||
// version
|
||||
4096 => '#650098',
|
||||
16 => '#E0B8FF',
|
||||
// data
|
||||
1024 => '#4A6000',
|
||||
4 => '#ECF9BE',
|
||||
// darkmodule
|
||||
512 => '#080063',
|
||||
// separator
|
||||
8 => '#AFBFBF',
|
||||
// quietzone
|
||||
18 => '#FFFFFF',
|
||||
],
|
||||
]);
|
||||
|
||||
echo (new QRCode($options))->render($data);
|
||||
|
||||
?>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
||||
|
||||
63
vendor/chillerlan/php-qrcode/examples/image.php
vendored
63
vendor/chillerlan/php-qrcode/examples/image.php
vendored
@@ -1,63 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* @filesource image.php
|
||||
* @created 24.12.2017
|
||||
* @author Smiley <smiley@chillerlan.net>
|
||||
* @copyright 2017 Smiley
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
namespace chillerlan\QRCodeExamples;
|
||||
|
||||
use chillerlan\QRCode\{QRCode, QROptions};
|
||||
|
||||
require_once __DIR__.'/../vendor/autoload.php';
|
||||
|
||||
$data = 'https://www.youtube.com/watch?v=DLzxrzFCyOs&t=43s';
|
||||
|
||||
$options = new QROptions([
|
||||
'version' => 10,
|
||||
'outputType' => QRCode::OUTPUT_IMAGE_PNG,
|
||||
'eccLevel' => QRCode::ECC_H,
|
||||
'scale' => 5,
|
||||
'imageBase64' => false,
|
||||
'moduleValues' => [
|
||||
// finder
|
||||
1536 => [0, 63, 255], // dark (true)
|
||||
6 => [255, 255, 255], // light (false), white is the transparency color and is enabled by default
|
||||
5632 => [241, 28, 163], // finder dot, dark (true)
|
||||
// alignment
|
||||
2560 => [255, 0, 255],
|
||||
10 => [255, 255, 255],
|
||||
// timing
|
||||
3072 => [255, 0, 0],
|
||||
12 => [255, 255, 255],
|
||||
// format
|
||||
3584 => [67, 99, 84],
|
||||
14 => [255, 255, 255],
|
||||
// version
|
||||
4096 => [62, 174, 190],
|
||||
16 => [255, 255, 255],
|
||||
// data
|
||||
1024 => [0, 0, 0],
|
||||
4 => [255, 255, 255],
|
||||
// darkmodule
|
||||
512 => [0, 0, 0],
|
||||
// separator
|
||||
8 => [255, 255, 255],
|
||||
// quietzone
|
||||
18 => [255, 255, 255],
|
||||
// logo (requires a call to QRMatrix::setLogoSpace())
|
||||
20 => [255, 255, 255],
|
||||
],
|
||||
]);
|
||||
|
||||
header('Content-type: image/png');
|
||||
|
||||
echo (new QRCode($options))->render($data);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* @filesource imageWithLogo.php
|
||||
* @created 18.11.2020
|
||||
* @author smiley <smiley@chillerlan.net>
|
||||
* @copyright 2020 smiley
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
namespace chillerlan\QRCodeExamples;
|
||||
|
||||
use chillerlan\QRCode\{QRCode, QROptions};
|
||||
|
||||
require_once __DIR__.'/../vendor/autoload.php';
|
||||
|
||||
$data = 'https://www.youtube.com/watch?v=DLzxrzFCyOs&t=43s';
|
||||
/**
|
||||
* @property int $logoSpaceWidth
|
||||
* @property int $logoSpaceHeight
|
||||
*
|
||||
* @noinspection PhpIllegalPsrClassPathInspection
|
||||
*/
|
||||
class LogoOptions extends QROptions{
|
||||
// size in QR modules, multiply with QROptions::$scale for pixel size
|
||||
protected int $logoSpaceWidth;
|
||||
protected int $logoSpaceHeight;
|
||||
}
|
||||
|
||||
$options = new LogoOptions;
|
||||
|
||||
$options->version = 7;
|
||||
$options->eccLevel = QRCode::ECC_H;
|
||||
$options->imageBase64 = false;
|
||||
$options->logoSpaceWidth = 13;
|
||||
$options->logoSpaceHeight = 13;
|
||||
$options->scale = 5;
|
||||
$options->imageTransparent = false;
|
||||
|
||||
header('Content-type: image/png');
|
||||
|
||||
$qrOutputInterface = new QRImageWithLogo($options, (new QRCode($options))->getMatrix($data));
|
||||
|
||||
// dump the output, with an additional logo
|
||||
echo $qrOutputInterface->dump(null, __DIR__.'/octocat.png');
|
||||
@@ -1,33 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* example for additional text
|
||||
* @link https://github.com/chillerlan/php-qrcode/issues/35
|
||||
*
|
||||
* @filesource imageWithText.php
|
||||
* @created 22.06.2019
|
||||
* @author Smiley <smiley@chillerlan.net>
|
||||
* @copyright 2019 Smiley
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
namespace chillerlan\QRCodeExamples;
|
||||
|
||||
use chillerlan\QRCode\{QRCode, QROptions};
|
||||
|
||||
require_once __DIR__.'/../vendor/autoload.php';
|
||||
|
||||
$data = 'https://www.youtube.com/watch?v=DLzxrzFCyOs&t=43s';
|
||||
|
||||
$options = new QROptions([
|
||||
'version' => 7,
|
||||
'outputType' => QRCode::OUTPUT_IMAGE_PNG,
|
||||
'scale' => 3,
|
||||
'imageBase64' => false,
|
||||
]);
|
||||
|
||||
header('Content-type: image/png');
|
||||
|
||||
$qrOutputInterface = new QRImageWithText($options, (new QRCode($options))->getMatrix($data));
|
||||
|
||||
// dump the output, with additional text
|
||||
echo $qrOutputInterface->dump(null, 'example text');
|
||||
@@ -1,59 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* @filesource image.php
|
||||
* @created 24.12.2017
|
||||
* @author Smiley <smiley@chillerlan.net>
|
||||
* @copyright 2017 Smiley
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
namespace chillerlan\QRCodeExamples;
|
||||
|
||||
use chillerlan\QRCode\{QRCode, QROptions};
|
||||
|
||||
require_once __DIR__.'/../vendor/autoload.php';
|
||||
|
||||
$data = 'https://www.youtube.com/watch?v=DLzxrzFCyOs&t=43s';
|
||||
|
||||
$options = new QROptions([
|
||||
'version' => 7,
|
||||
'outputType' => QRCode::OUTPUT_IMAGICK,
|
||||
'eccLevel' => QRCode::ECC_L,
|
||||
'scale' => 5,
|
||||
'moduleValues' => [
|
||||
// finder
|
||||
1536 => '#A71111', // dark (true)
|
||||
6 => '#FFBFBF', // light (false)
|
||||
// alignment
|
||||
2560 => '#A70364',
|
||||
10 => '#FFC9C9',
|
||||
// timing
|
||||
3072 => '#98005D',
|
||||
12 => '#FFB8E9',
|
||||
// format
|
||||
3584 => '#003804',
|
||||
14 => '#00FB12',
|
||||
// version
|
||||
4096 => '#650098',
|
||||
16 => '#E0B8FF',
|
||||
// data
|
||||
1024 => '#4A6000',
|
||||
4 => '#ECF9BE',
|
||||
// darkmodule
|
||||
512 => '#080063',
|
||||
// separator
|
||||
8 => '#DDDDDD',
|
||||
// quietzone
|
||||
18 => '#DDDDDD',
|
||||
],
|
||||
]);
|
||||
|
||||
header('Content-type: image/png');
|
||||
|
||||
echo (new QRCode($options))->render($data);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
BIN
vendor/chillerlan/php-qrcode/examples/octocat.png
vendored
BIN
vendor/chillerlan/php-qrcode/examples/octocat.png
vendored
Binary file not shown.
|
Before Width: | Height: | Size: 2.4 KiB |
78
vendor/chillerlan/php-qrcode/examples/svg.php
vendored
78
vendor/chillerlan/php-qrcode/examples/svg.php
vendored
@@ -1,78 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* @filesource svg.php
|
||||
* @created 21.12.2017
|
||||
* @author Smiley <smiley@chillerlan.net>
|
||||
* @copyright 2017 Smiley
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
namespace chillerlan\QRCodeExamples;
|
||||
|
||||
use chillerlan\QRCode\{QRCode, QROptions};
|
||||
|
||||
require_once __DIR__.'/../vendor/autoload.php';
|
||||
|
||||
$data = 'https://www.youtube.com/watch?v=DLzxrzFCyOs&t=43s';
|
||||
$gzip = true;
|
||||
|
||||
$options = new QROptions([
|
||||
'version' => 7,
|
||||
'outputType' => QRCode::OUTPUT_MARKUP_SVG,
|
||||
'imageBase64' => false,
|
||||
'eccLevel' => QRCode::ECC_L,
|
||||
'svgViewBoxSize' => 530,
|
||||
'addQuietzone' => true,
|
||||
'cssClass' => 'my-css-class',
|
||||
'svgOpacity' => 1.0,
|
||||
'svgDefs' => '
|
||||
<linearGradient id="g2">
|
||||
<stop offset="0%" stop-color="#39F" />
|
||||
<stop offset="100%" stop-color="#F3F" />
|
||||
</linearGradient>
|
||||
<linearGradient id="g1">
|
||||
<stop offset="0%" stop-color="#F3F" />
|
||||
<stop offset="100%" stop-color="#39F" />
|
||||
</linearGradient>
|
||||
<style>rect{shape-rendering:crispEdges}</style>',
|
||||
'moduleValues' => [
|
||||
// finder
|
||||
1536 => 'url(#g1)', // dark (true)
|
||||
6 => '#fff', // light (false)
|
||||
// alignment
|
||||
2560 => 'url(#g1)',
|
||||
10 => '#fff',
|
||||
// timing
|
||||
3072 => 'url(#g1)',
|
||||
12 => '#fff',
|
||||
// format
|
||||
3584 => 'url(#g1)',
|
||||
14 => '#fff',
|
||||
// version
|
||||
4096 => 'url(#g1)',
|
||||
16 => '#fff',
|
||||
// data
|
||||
1024 => 'url(#g2)',
|
||||
4 => '#fff',
|
||||
// darkmodule
|
||||
512 => 'url(#g1)',
|
||||
// separator
|
||||
8 => '#fff',
|
||||
// quietzone
|
||||
18 => '#fff',
|
||||
],
|
||||
]);
|
||||
|
||||
$qrcode = (new QRCode($options))->render($data);
|
||||
|
||||
header('Content-type: image/svg+xml');
|
||||
|
||||
if($gzip === true){
|
||||
header('Vary: Accept-Encoding');
|
||||
header('Content-Encoding: gzip');
|
||||
$qrcode = gzencode($qrcode ,9);
|
||||
}
|
||||
echo $qrcode;
|
||||
|
||||
|
||||
68
vendor/chillerlan/php-qrcode/examples/text.php
vendored
68
vendor/chillerlan/php-qrcode/examples/text.php
vendored
@@ -1,68 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* @filesource text.php
|
||||
* @created 21.12.2017
|
||||
* @author Smiley <smiley@chillerlan.net>
|
||||
* @copyright 2017 Smiley
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
namespace chillerlan\QRCodeExamples;
|
||||
|
||||
use chillerlan\QRCode\{QRCode, QROptions};
|
||||
|
||||
require_once __DIR__.'/../vendor/autoload.php';
|
||||
|
||||
$data = 'https://www.youtube.com/watch?v=DLzxrzFCyOs&t=43s';
|
||||
|
||||
$options = new QROptions([
|
||||
'version' => 5,
|
||||
'outputType' => QRCode::OUTPUT_STRING_TEXT,
|
||||
'eccLevel' => QRCode::ECC_L,
|
||||
]);
|
||||
|
||||
// <pre> to view it in a browser
|
||||
echo '<pre style="font-size: 75%; line-height: 1;">'.(new QRCode($options))->render($data).'</pre>';
|
||||
|
||||
|
||||
// custom values
|
||||
$options = new QROptions([
|
||||
'version' => 5,
|
||||
'outputType' => QRCode::OUTPUT_STRING_TEXT,
|
||||
'eccLevel' => QRCode::ECC_L,
|
||||
'moduleValues' => [
|
||||
// finder
|
||||
1536 => 'A', // dark (true)
|
||||
6 => 'a', // light (false)
|
||||
// alignment
|
||||
2560 => 'B',
|
||||
10 => 'b',
|
||||
// timing
|
||||
3072 => 'C',
|
||||
12 => 'c',
|
||||
// format
|
||||
3584 => 'D',
|
||||
14 => 'd',
|
||||
// version
|
||||
4096 => 'E',
|
||||
16 => 'e',
|
||||
// data
|
||||
1024 => 'F',
|
||||
4 => 'f',
|
||||
// darkmodule
|
||||
512 => 'G',
|
||||
// separator
|
||||
8 => 'h',
|
||||
// quietzone
|
||||
18 => 'i',
|
||||
],
|
||||
]);
|
||||
|
||||
// <pre> to view it in a browser
|
||||
echo '<pre style="font-size: 75%; line-height: 1;">'.(new QRCode($options))->render($data).'</pre>';
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
20
vendor/chillerlan/php-qrcode/phpdoc.xml
vendored
20
vendor/chillerlan/php-qrcode/phpdoc.xml
vendored
@@ -1,20 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<phpdoc>
|
||||
<parser>
|
||||
<target>docs</target>
|
||||
<encoding>utf8</encoding>
|
||||
<markers>
|
||||
<item>TODO</item>
|
||||
</markers>
|
||||
</parser>
|
||||
<transformer>
|
||||
<target>docs</target>
|
||||
</transformer>
|
||||
<files>
|
||||
<directory>src</directory>
|
||||
<directory>tests</directory>
|
||||
</files>
|
||||
<transformations>
|
||||
<template name="responsive-twig"/>
|
||||
</transformations>
|
||||
</phpdoc>
|
||||
26
vendor/chillerlan/php-qrcode/phpunit.xml
vendored
26
vendor/chillerlan/php-qrcode/phpunit.xml
vendored
@@ -1,26 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.5/phpunit.xsd"
|
||||
bootstrap="vendor/autoload.php"
|
||||
cacheResultFile=".build/phpunit.result.cache"
|
||||
colors="true"
|
||||
verbose="true"
|
||||
>
|
||||
<coverage processUncoveredFiles="true">
|
||||
<include>
|
||||
<directory suffix=".php">./src</directory>
|
||||
</include>
|
||||
<report>
|
||||
<clover outputFile=".build/coverage/clover.xml"/>
|
||||
<xml outputDirectory=".build/coverage/coverage-xml"/>
|
||||
</report>
|
||||
</coverage>
|
||||
<testsuites>
|
||||
<testsuite name="php-qrcode test suite">
|
||||
<directory suffix=".php">./tests/</directory>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
<logging>
|
||||
<junit outputFile=".build/logs/junit.xml"/>
|
||||
</logging>
|
||||
</phpunit>
|
||||
163
vendor/chillerlan/php-qrcode/public/index.html
vendored
163
vendor/chillerlan/php-qrcode/public/index.html
vendored
@@ -1,163 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" >
|
||||
<head >
|
||||
<meta charset="UTF-8" >
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title >QR Code Generator</title >
|
||||
<style >
|
||||
body{ font-size: 20px; line-height: 1.4em; font-family: "Trebuchet MS", sans-serif; color: #000;}
|
||||
input, textarea, select{font-family: Consolas, "Liberation Mono", Courier, monospace; font-size: 75%; line-height: 1.25em; border: 1px solid #aaa; }
|
||||
input:focus, textarea:focus, select:focus{ border: 1px solid #ccc; }
|
||||
label{ cursor: pointer; }
|
||||
#qrcode-settings, div#qrcode-output{ text-align: center; }
|
||||
div#qrcode-output > div {margin: 0;padding: 0;height: 3px;}
|
||||
div#qrcode-output > div > span {display: inline-block;width: 3px;height: 3px;}
|
||||
div#qrcode-output > div > span {background-color: lightgrey;}
|
||||
</style >
|
||||
</head >
|
||||
<body >
|
||||
|
||||
<form id="qrcode-settings" >
|
||||
|
||||
<label for="inputstring" >Input String</label ><br /><textarea name="inputstring" id="inputstring" cols="80" rows="3" autocomplete="off" spellcheck="false"></textarea ><br />
|
||||
|
||||
<label for="version" >Version</label >
|
||||
<input id="version" name="version" class="options" type="number" min="1" max="40" value="5" placeholder="version" />
|
||||
|
||||
<label for="maskpattern" >Mask Pattern</label >
|
||||
<input id="maskpattern" name="maskpattern" class="options" type="number" min="-1" max="7" value="-1" placeholder="mask pattern" />
|
||||
|
||||
<label for="ecc" >ECC</label >
|
||||
<select class="options" id="ecc" name="ecc" >
|
||||
<option value="L" selected="selected" >L - 7%</option >
|
||||
<option value="M" >M - 15%</option >
|
||||
<option value="Q" >Q - 25%</option >
|
||||
<option value="H" >H - 30%</option >
|
||||
</select >
|
||||
|
||||
<br />
|
||||
|
||||
<label for="quietzone" >Quiet Zone
|
||||
<input id="quietzone" name="quietzone" class="options" type="checkbox" value="true" />
|
||||
</label >
|
||||
|
||||
<label for="quietzonesize" >size</label >
|
||||
<input id="quietzonesize" name="quietzonesize" class="options" type="number" min="0" max="100" value="4" placeholder="quiet zone" />
|
||||
|
||||
<br />
|
||||
|
||||
<label for="output_type" >Output</label >
|
||||
<select class="options" id="output_type" name="output_type" >
|
||||
<option value="html" >Markup - HTML</option >
|
||||
<option value="svg" selected="selected" >Markup - SVG</option >
|
||||
<option value="png">Image - png</option >
|
||||
<option value="jpg" >Image - jpg</option >
|
||||
<option value="gif" >Image - gif</option >
|
||||
<option value="text" >String - text</option >
|
||||
<option value="json" >String - json</option >
|
||||
</select >
|
||||
|
||||
<label for="scale" >scale</label >
|
||||
<input id="scale" name="scale" class="options" type="number" min="1" max="10" value="5" placeholder="scale" />
|
||||
|
||||
<div>Finder</div>
|
||||
<label for="m_finder_light" >
|
||||
<input type="text" id="m_finder_light" name="m_finder_light" class="jscolor options" value="ffffff" autocomplete="off" spellcheck="false" minlength="6" maxlength="6" />
|
||||
</label >
|
||||
<label for="m_finder_dark" >
|
||||
<input type="text" id="m_finder_dark" name="m_finder_dark" class="jscolor options" value="000000" autocomplete="off" spellcheck="false" minlength="6" maxlength="6" />
|
||||
</label >
|
||||
|
||||
<div>Alignment</div>
|
||||
<label for="m_alignment_light" >
|
||||
<input type="text" id="m_alignment_light" name="m_alignment_light" class="jscolor options" value="ffffff" autocomplete="off" spellcheck="false" minlength="6" maxlength="6" />
|
||||
</label >
|
||||
<label for="m_alignment_dark" >
|
||||
<input type="text" id="m_alignment_dark" name="m_alignment_dark" class="jscolor options" value="000000" autocomplete="off" spellcheck="false" minlength="6" maxlength="6" />
|
||||
</label >
|
||||
|
||||
<div>Timing</div>
|
||||
<label for="m_timing_light" >
|
||||
<input type="text" id="m_timing_light" name="m_timing_light" class="jscolor options" value="ffffff" autocomplete="off" spellcheck="false" minlength="6" maxlength="6" />
|
||||
</label >
|
||||
<label for="m_timing_dark" >
|
||||
<input type="text" id="m_timing_dark" name="m_timing_dark" class="jscolor options" value="000000" autocomplete="off" spellcheck="false" minlength="6" maxlength="6" />
|
||||
</label >
|
||||
|
||||
<div>Format</div>
|
||||
<label for="m_format_light" >
|
||||
<input type="text" id="m_format_light" name="m_format_light" class="jscolor options" value="ffffff" autocomplete="off" spellcheck="false" minlength="6" maxlength="6" />
|
||||
</label >
|
||||
<label for="m_format_dark" >
|
||||
<input type="text" id="m_format_dark" name="m_format_dark" class="jscolor options" value="000000" autocomplete="off" spellcheck="false" minlength="6" maxlength="6" />
|
||||
</label >
|
||||
|
||||
<div>Version</div>
|
||||
<label for="m_version_light" >
|
||||
<input type="text" id="m_version_light" name="m_version_light" class="jscolor options" value="ffffff" autocomplete="off" spellcheck="false" minlength="6" maxlength="6" />
|
||||
</label >
|
||||
<label for="m_version_dark" >
|
||||
<input type="text" id="m_version_dark" name="m_version_dark" class="jscolor options" value="000000" autocomplete="off" spellcheck="false" minlength="6" maxlength="6" />
|
||||
</label >
|
||||
|
||||
<div>Data</div>
|
||||
<label for="m_data_light" >
|
||||
<input type="text" id="m_data_light" name="m_data_light" class="jscolor options" value="ffffff" autocomplete="off" spellcheck="false" minlength="6" maxlength="6" />
|
||||
</label >
|
||||
<label for="m_data_dark" >
|
||||
<input type="text" id="m_data_dark" name="m_data_dark" class="jscolor options" value="000000" autocomplete="off" spellcheck="false" minlength="6" maxlength="6" />
|
||||
</label >
|
||||
|
||||
<div>Dark Module</div>
|
||||
<label for="m_darkmodule_light" >
|
||||
<input disabled="disabled" type="text" id="m_darkmodule_light" class="options" value="" autocomplete="off" spellcheck="false" />
|
||||
</label >
|
||||
<label for="m_darkmodule_dark" >
|
||||
<input type="text" id="m_darkmodule_dark" name="m_darkmodule_dark" class="jscolor options" value="000000" autocomplete="off" spellcheck="false" minlength="6" maxlength="6" />
|
||||
</label >
|
||||
|
||||
<div>Separator</div>
|
||||
<label for="m_separator_light" >
|
||||
<input type="text" id="m_separator_light" name="m_separator_light" class="jscolor options" value="ffffff" autocomplete="off" spellcheck="false" minlength="6" maxlength="6" />
|
||||
</label >
|
||||
<label for="m_separator_dark" >
|
||||
<input disabled="disabled" type="text" id="m_separator_dark" class="options" value="" autocomplete="off" spellcheck="false" />
|
||||
</label >
|
||||
|
||||
<div>Quiet Zone</div>
|
||||
<label for="m_quietzone_light" >
|
||||
<input type="text" id="m_quietzone_light" name="m_quietzone_light" class="jscolor options" value="ffffff" autocomplete="off" spellcheck="false" minlength="6" maxlength="6" />
|
||||
</label >
|
||||
<label for="m_quietzone_dark" >
|
||||
<input disabled="disabled" type="text" id="m_quietzone_dark" class="options" value="" autocomplete="off" spellcheck="false" />
|
||||
</label >
|
||||
|
||||
<br />
|
||||
<button type="submit" >generate</button >
|
||||
</form >
|
||||
<div id="qrcode-output" ></div >
|
||||
|
||||
<div><a href="https://play.google.com/store/apps/details?id=com.google.zxing.client.android" >ZXing Barcode Scanner</a ></div>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/prototype/1.7.3/prototype.js" ></script >
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/jscolor/2.0.4/jscolor.js" ></script >
|
||||
<script >
|
||||
((form, output, url) => {
|
||||
|
||||
$(form).observe('submit', ev => {
|
||||
Event.stop(ev);
|
||||
|
||||
new Ajax.Request(url, {
|
||||
method: 'post',
|
||||
parameters: ev.target.serialize(true),
|
||||
onUninitialized: $(output).update(),
|
||||
onLoading: $(output).update('[portlandia_screaming.gif]'),
|
||||
onFailure: response => $(output).update(response.responseJSON.error),
|
||||
onSuccess: response => $(output).update(response.responseJSON.qrcode),
|
||||
});
|
||||
|
||||
});
|
||||
})('qrcode-settings', 'qrcode-output', './qrcode.php');
|
||||
</script >
|
||||
|
||||
</body >
|
||||
</html >
|
||||
97
vendor/chillerlan/php-qrcode/public/qrcode.php
vendored
97
vendor/chillerlan/php-qrcode/public/qrcode.php
vendored
@@ -1,97 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* @filesource qrcode.php
|
||||
* @created 18.11.2017
|
||||
* @author Smiley <smiley@chillerlan.net>
|
||||
* @copyright 2017 Smiley
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
namespace chillerlan\QRCodePublic;
|
||||
|
||||
use chillerlan\QRCode\QRCode;
|
||||
use chillerlan\QRCode\QROptions;
|
||||
|
||||
require_once '../vendor/autoload.php';
|
||||
|
||||
try{
|
||||
|
||||
$moduleValues = [
|
||||
// finder
|
||||
1536 => $_POST['m_finder_dark'],
|
||||
6 => $_POST['m_finder_light'],
|
||||
// alignment
|
||||
2560 => $_POST['m_alignment_dark'],
|
||||
10 => $_POST['m_alignment_light'],
|
||||
// timing
|
||||
3072 => $_POST['m_timing_dark'],
|
||||
12 => $_POST['m_timing_light'],
|
||||
// format
|
||||
3584 => $_POST['m_format_dark'],
|
||||
14 => $_POST['m_format_light'],
|
||||
// version
|
||||
4096 => $_POST['m_version_dark'],
|
||||
16 => $_POST['m_version_light'],
|
||||
// data
|
||||
1024 => $_POST['m_data_dark'],
|
||||
4 => $_POST['m_data_light'],
|
||||
// darkmodule
|
||||
512 => $_POST['m_darkmodule_dark'],
|
||||
// separator
|
||||
8 => $_POST['m_separator_light'],
|
||||
// quietzone
|
||||
18 => $_POST['m_quietzone_light'],
|
||||
];
|
||||
|
||||
$moduleValues = array_map(function($v){
|
||||
if(preg_match('/[a-f\d]{6}/i', $v) === 1){
|
||||
return in_array($_POST['output_type'], ['png', 'jpg', 'gif'])
|
||||
? array_map('hexdec', str_split($v, 2))
|
||||
: '#'.$v ;
|
||||
}
|
||||
return null;
|
||||
}, $moduleValues);
|
||||
|
||||
|
||||
$ecc = in_array($_POST['ecc'], ['L', 'M', 'Q', 'H'], true) ? $_POST['ecc'] : 'L';
|
||||
|
||||
$qro = new QROptions;
|
||||
|
||||
$qro->version = (int)$_POST['version'];
|
||||
$qro->eccLevel = constant('chillerlan\\QRCode\\QRCode::ECC_'.$ecc);
|
||||
$qro->maskPattern = (int)$_POST['maskpattern'];
|
||||
$qro->addQuietzone = isset($_POST['quietzone']);
|
||||
$qro->quietzoneSize = (int)$_POST['quietzonesize'];
|
||||
$qro->moduleValues = $moduleValues;
|
||||
$qro->outputType = $_POST['output_type'];
|
||||
$qro->scale = (int)$_POST['scale'];
|
||||
$qro->imageTransparent = false;
|
||||
|
||||
$qrcode = (new QRCode($qro))->render($_POST['inputstring']);
|
||||
|
||||
if(in_array($_POST['output_type'], ['png', 'jpg', 'gif'])){
|
||||
$qrcode = '<img src="'.$qrcode.'" />';
|
||||
}
|
||||
elseif($_POST['output_type'] === 'text'){
|
||||
$qrcode = '<pre style="font-size: 75%; line-height: 1;">'.$qrcode.'</pre>';
|
||||
}
|
||||
elseif($_POST['output_type'] === 'json'){
|
||||
$qrcode = '<pre style="font-size: 75%; overflow-x: auto;">'.$qrcode.'</pre>';
|
||||
}
|
||||
|
||||
send_response(['qrcode' => $qrcode]);
|
||||
}
|
||||
// Pokémon exception handler
|
||||
catch(\Exception $e){
|
||||
header('HTTP/1.1 500 Internal Server Error');
|
||||
send_response(['error' => $e->getMessage()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $response
|
||||
*/
|
||||
function send_response(array $response){
|
||||
header('Content-type: application/json;charset=utf-8;');
|
||||
echo json_encode($response);
|
||||
exit;
|
||||
}
|
||||
@@ -130,7 +130,7 @@ final class MaskPatternTester{
|
||||
}
|
||||
|
||||
if(
|
||||
$val === $m[$y][$x + 1]
|
||||
$val === $row[$x + 1]
|
||||
&& $val === $m[$y + 1][$x]
|
||||
&& $val === $m[$y + 1][$x + 1]
|
||||
){
|
||||
@@ -154,12 +154,12 @@ final class MaskPatternTester{
|
||||
if(
|
||||
$x + 6 < $size
|
||||
&& $val
|
||||
&& !$m[$y][$x + 1]
|
||||
&& $m[$y][$x + 2]
|
||||
&& $m[$y][$x + 3]
|
||||
&& $m[$y][$x + 4]
|
||||
&& !$m[$y][$x + 5]
|
||||
&& $m[$y][$x + 6]
|
||||
&& !$row[$x + 1]
|
||||
&& $row[$x + 2]
|
||||
&& $row[$x + 3]
|
||||
&& $row[$x + 4]
|
||||
&& !$row[$x + 5]
|
||||
&& $row[$x + 6]
|
||||
){
|
||||
$penalties++;
|
||||
}
|
||||
@@ -189,8 +189,8 @@ final class MaskPatternTester{
|
||||
protected function testLevel4(array $m, int $size):float{
|
||||
$count = 0;
|
||||
|
||||
foreach($m as $y => $row){
|
||||
foreach($row as $x => $val){
|
||||
foreach($m as $row){
|
||||
foreach($row as $val){
|
||||
if($val){
|
||||
$count++;
|
||||
}
|
||||
|
||||
@@ -70,7 +70,7 @@ abstract class QRDataAbstract implements QRDataInterface{
|
||||
/**
|
||||
* QRDataInterface constructor.
|
||||
*/
|
||||
public function __construct(SettingsContainerInterface $options, string $data = null){
|
||||
public function __construct(SettingsContainerInterface $options, ?string $data = null){
|
||||
$this->options = $options;
|
||||
|
||||
if($data !== null){
|
||||
@@ -100,7 +100,7 @@ abstract class QRDataAbstract implements QRDataInterface{
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function initMatrix(int $maskPattern, bool $test = null):QRMatrix{
|
||||
public function initMatrix(int $maskPattern, ?bool $test = null):QRMatrix{
|
||||
return (new QRMatrix($this->version, $this->options->eccLevel))
|
||||
->init($maskPattern, $test)
|
||||
->mapData($this->maskECC(), $maskPattern)
|
||||
|
||||
@@ -21,7 +21,7 @@ interface QRDataInterface{
|
||||
/**
|
||||
* @var int[]
|
||||
*/
|
||||
const CHAR_MAP_NUMBER = [
|
||||
public const CHAR_MAP_NUMBER = [
|
||||
'0' => 0, '1' => 1, '2' => 2, '3' => 3, '4' => 4, '5' => 5, '6' => 6, '7' => 7, '8' => 8, '9' => 9,
|
||||
];
|
||||
|
||||
@@ -30,7 +30,7 @@ interface QRDataInterface{
|
||||
*
|
||||
* @var int[]
|
||||
*/
|
||||
const CHAR_MAP_ALPHANUM = [
|
||||
public const CHAR_MAP_ALPHANUM = [
|
||||
'0' => 0, '1' => 1, '2' => 2, '3' => 3, '4' => 4, '5' => 5, '6' => 6, '7' => 7,
|
||||
'8' => 8, '9' => 9, 'A' => 10, 'B' => 11, 'C' => 12, 'D' => 13, 'E' => 14, 'F' => 15,
|
||||
'G' => 16, 'H' => 17, 'I' => 18, 'J' => 19, 'K' => 20, 'L' => 21, 'M' => 22, 'N' => 23,
|
||||
@@ -46,7 +46,7 @@ interface QRDataInterface{
|
||||
*
|
||||
* @var int [][][]
|
||||
*/
|
||||
const MAX_LENGTH =[
|
||||
public const MAX_LENGTH =[
|
||||
// v => [NUMERIC => [L, M, Q, H ], ALPHANUM => [L, M, Q, H], BINARY => [L, M, Q, H ], KANJI => [L, M, Q, H ]] // modules
|
||||
1 => [[ 41, 34, 27, 17], [ 25, 20, 16, 10], [ 17, 14, 11, 7], [ 10, 8, 7, 4]], // 21
|
||||
2 => [[ 77, 63, 48, 34], [ 47, 38, 29, 20], [ 32, 26, 20, 14], [ 20, 16, 12, 8]], // 25
|
||||
@@ -95,7 +95,7 @@ interface QRDataInterface{
|
||||
*
|
||||
* @var int [][]
|
||||
*/
|
||||
const MAX_BITS = [
|
||||
public const MAX_BITS = [
|
||||
// version => [L, M, Q, H ]
|
||||
1 => [ 152, 128, 104, 72],
|
||||
2 => [ 272, 224, 176, 128],
|
||||
@@ -144,7 +144,7 @@ interface QRDataInterface{
|
||||
*
|
||||
* @var int [][][]
|
||||
*/
|
||||
const RSBLOCKS = [
|
||||
public const RSBLOCKS = [
|
||||
1 => [[ 1, 0, 26, 19], [ 1, 0, 26, 16], [ 1, 0, 26, 13], [ 1, 0, 26, 9]],
|
||||
2 => [[ 1, 0, 44, 34], [ 1, 0, 44, 28], [ 1, 0, 44, 22], [ 1, 0, 44, 16]],
|
||||
3 => [[ 1, 0, 70, 55], [ 1, 0, 70, 44], [ 2, 0, 35, 17], [ 2, 0, 35, 13]],
|
||||
@@ -195,6 +195,6 @@ interface QRDataInterface{
|
||||
/**
|
||||
* returns a fresh matrix object with the data written for the given $maskPattern
|
||||
*/
|
||||
public function initMatrix(int $maskPattern, bool $test = null):QRMatrix;
|
||||
public function initMatrix(int $maskPattern, ?bool $test = null):QRMatrix;
|
||||
|
||||
}
|
||||
|
||||
@@ -25,32 +25,71 @@ use function array_fill, array_key_exists, array_push, array_unshift, count, flo
|
||||
*/
|
||||
final class QRMatrix{
|
||||
|
||||
/*
|
||||
* special values
|
||||
*/
|
||||
|
||||
/** @var int */
|
||||
public const M_NULL = 0x00;
|
||||
public const M_NULL = 0x00;
|
||||
/** @var int */
|
||||
public const M_DARKMODULE = 0x02;
|
||||
public const M_LOGO = 0x14;
|
||||
/** @var int */
|
||||
public const M_DATA = 0x04;
|
||||
public const M_LOGO_DARK = self::M_LOGO << 8;
|
||||
|
||||
/*
|
||||
* light values
|
||||
*/
|
||||
|
||||
/** @var int */
|
||||
public const M_FINDER = 0x06;
|
||||
public const M_DATA = 0x04;
|
||||
/** @var int */
|
||||
public const M_SEPARATOR = 0x08;
|
||||
public const M_FINDER = 0x06;
|
||||
/** @var int */
|
||||
public const M_ALIGNMENT = 0x0a;
|
||||
public const M_SEPARATOR = 0x08;
|
||||
/** @var int */
|
||||
public const M_TIMING = 0x0c;
|
||||
public const M_ALIGNMENT = 0x0a;
|
||||
/** @var int */
|
||||
public const M_FORMAT = 0x0e;
|
||||
public const M_TIMING = 0x0c;
|
||||
/** @var int */
|
||||
public const M_VERSION = 0x10;
|
||||
public const M_FORMAT = 0x0e;
|
||||
/** @var int */
|
||||
public const M_QUIETZONE = 0x12;
|
||||
public const M_VERSION = 0x10;
|
||||
/** @var int */
|
||||
public const M_LOGO = 0x14;
|
||||
public const M_QUIETZONE = 0x12;
|
||||
|
||||
/*
|
||||
* dark values
|
||||
*/
|
||||
|
||||
/** @var int */
|
||||
public const M_FINDER_DOT = 0x16;
|
||||
public const M_DARKMODULE = self::M_DARKMODULE_LIGHT << 8;
|
||||
/** @var int */
|
||||
public const M_TEST = 0xff;
|
||||
public const M_DATA_DARK = self::M_DATA << 8;
|
||||
/** @var int */
|
||||
public const M_FINDER_DARK = self::M_FINDER << 8;
|
||||
/** @var int */
|
||||
public const M_ALIGNMENT_DARK = self::M_ALIGNMENT << 8;
|
||||
/** @var int */
|
||||
public const M_TIMING_DARK = self::M_TIMING << 8;
|
||||
/** @var int */
|
||||
public const M_FORMAT_DARK = self::M_FORMAT << 8;
|
||||
/** @var int */
|
||||
public const M_VERSION_DARK = self::M_VERSION << 8;
|
||||
/** @var int */
|
||||
public const M_FINDER_DOT = self::M_FINDER_DOT_LIGHT << 8;
|
||||
|
||||
/*
|
||||
* values used for reversed reflectance
|
||||
*/
|
||||
|
||||
/** @var int */
|
||||
public const M_DARKMODULE_LIGHT = 0x02;
|
||||
/** @var int */
|
||||
public const M_FINDER_DOT_LIGHT = 0x16;
|
||||
/** @var int */
|
||||
public const M_SEPARATOR_DARK = self::M_SEPARATOR << 8;
|
||||
/** @var int */
|
||||
public const M_QUIETZONE_DARK = self::M_QUIETZONE << 8;
|
||||
|
||||
/**
|
||||
* ISO/IEC 18004:2000 Annex E, Table E.1 - Row/column coordinates of center module of Alignment Patterns
|
||||
@@ -247,7 +286,7 @@ final class QRMatrix{
|
||||
/**
|
||||
* shortcut to initialize the matrix
|
||||
*/
|
||||
public function init(int $maskPattern, bool $test = null):QRMatrix{
|
||||
public function init(int $maskPattern, ?bool $test = null):QRMatrix{
|
||||
return $this
|
||||
->setFinderPattern()
|
||||
->setSeparators()
|
||||
@@ -350,7 +389,7 @@ final class QRMatrix{
|
||||
* Sets the "dark module", that is always on the same position 1x1px away from the bottom left finder
|
||||
*/
|
||||
public function setDarkModule():QRMatrix{
|
||||
$this->set(8, 4 * $this->version + 9, true, $this::M_DARKMODULE);
|
||||
$this->set(8, 4 * $this->version + 9, true, $this::M_DARKMODULE_LIGHT);
|
||||
|
||||
return $this;
|
||||
}
|
||||
@@ -364,8 +403,8 @@ final class QRMatrix{
|
||||
|
||||
$pos = [
|
||||
[0, 0], // top left
|
||||
[$this->moduleCount - 7, 0], // bottom left
|
||||
[0, $this->moduleCount - 7], // top right
|
||||
[$this->moduleCount - 7, 0], // top right
|
||||
[0, $this->moduleCount - 7], // bottom left
|
||||
];
|
||||
|
||||
foreach($pos as $c){
|
||||
@@ -381,7 +420,7 @@ final class QRMatrix{
|
||||
}
|
||||
// 3*3 dot
|
||||
else{
|
||||
$this->set($c[0] + $y, $c[1] + $x, true, $this::M_FINDER_DOT);
|
||||
$this->set($c[0] + $y, $c[1] + $x, true, $this::M_FINDER_DOT_LIGHT);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -477,7 +516,7 @@ final class QRMatrix{
|
||||
*
|
||||
* ISO/IEC 18004:2000 Section 8.10
|
||||
*/
|
||||
public function setVersionNumber(bool $test = null):QRMatrix{
|
||||
public function setVersionNumber(?bool $test = null):QRMatrix{
|
||||
$bits = $this::versionPattern[$this->version] ?? false;
|
||||
|
||||
if($bits !== false){
|
||||
@@ -501,7 +540,7 @@ final class QRMatrix{
|
||||
*
|
||||
* ISO/IEC 18004:2000 Section 8.9
|
||||
*/
|
||||
public function setFormatInfo(int $maskPattern, bool $test = null):QRMatrix{
|
||||
public function setFormatInfo(int $maskPattern, ?bool $test = null):QRMatrix{
|
||||
$bits = $this::formatPattern[QRCode::ECC_MODES[$this->eclevel]][$maskPattern] ?? 0;
|
||||
|
||||
for($i = 0; $i < 15; $i++){
|
||||
@@ -541,7 +580,7 @@ final class QRMatrix{
|
||||
*
|
||||
* @throws \chillerlan\QRCode\Data\QRCodeDataException
|
||||
*/
|
||||
public function setQuietZone(int $size = null):QRMatrix{
|
||||
public function setQuietZone(?int $size = null):QRMatrix{
|
||||
|
||||
if($this->matrix[$this->moduleCount - 1][$this->moduleCount - 1] === $this::M_NULL){
|
||||
throw new QRCodeDataException('use only after writing data');
|
||||
@@ -588,7 +627,7 @@ final class QRMatrix{
|
||||
*
|
||||
* @throws \chillerlan\QRCode\Data\QRCodeDataException
|
||||
*/
|
||||
public function setLogoSpace(int $width, int $height, int $startX = null, int $startY = null):QRMatrix{
|
||||
public function setLogoSpace(int $width, int $height, ?int $startX = null, ?int $startY = null):QRMatrix{
|
||||
|
||||
// for logos we operate in ECC H (30%) only
|
||||
if($this->eclevel !== QRCode::ECC_H){
|
||||
@@ -624,8 +663,8 @@ final class QRMatrix{
|
||||
$startY = ($startY !== null ? $startY : ($length - $height) / 2) + $qz;
|
||||
|
||||
// clear the space
|
||||
foreach($this->matrix as $y => $row){
|
||||
foreach($row as $x => $val){
|
||||
for($y = 0; $y < $this->moduleCount; $y++){
|
||||
for($x = 0; $x < $this->moduleCount; $x++){
|
||||
// out of bounds, skip
|
||||
if($x < $start || $y < $start ||$x >= $end || $y >= $end){
|
||||
continue;
|
||||
|
||||
@@ -69,7 +69,7 @@ final class Polynomial{
|
||||
/**
|
||||
* Polynomial constructor.
|
||||
*/
|
||||
public function __construct(array $num = null, int $shift = null){
|
||||
public function __construct(?array $num = null, ?int $shift = null){
|
||||
$this->setNum($num ?? [1], $shift);
|
||||
}
|
||||
|
||||
@@ -86,7 +86,7 @@ final class Polynomial{
|
||||
*
|
||||
* @return \chillerlan\QRCode\Helpers\Polynomial
|
||||
*/
|
||||
public function setNum(array $num, int $shift = null):Polynomial{
|
||||
public function setNum(array $num, ?int $shift = null):Polynomial{
|
||||
$offset = 0;
|
||||
$numCount = count($num);
|
||||
|
||||
@@ -157,7 +157,7 @@ final class Polynomial{
|
||||
throw new QRCodeException(sprintf('log(%s)', $n));
|
||||
}
|
||||
|
||||
return Polynomial::table[$n][1];
|
||||
return self::table[$n][1];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -172,7 +172,7 @@ final class Polynomial{
|
||||
$n -= 255;
|
||||
}
|
||||
|
||||
return Polynomial::table[$n][0];
|
||||
return self::table[$n][0];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -68,7 +68,7 @@ class QRFpdf extends QROutputAbstract{
|
||||
*
|
||||
* @return string|\FPDF
|
||||
*/
|
||||
public function dump(string $file = null){
|
||||
public function dump(?string $file = null){
|
||||
$file ??= $this->options->cachefile;
|
||||
|
||||
$fpdf = new FPDF('P', $this->options->fpdfMeasureUnit, [$this->length, $this->length]);
|
||||
|
||||
@@ -94,7 +94,7 @@ class QRImage extends QROutputAbstract{
|
||||
*
|
||||
* @phan-suppress PhanUndeclaredTypeReturnType, PhanTypeMismatchReturn
|
||||
*/
|
||||
public function dump(string $file = null){
|
||||
public function dump(?string $file = null){
|
||||
$file ??= $this->options->cachefile;
|
||||
|
||||
$this->image = imagecreatetruecolor($this->length, $this->length);
|
||||
|
||||
@@ -67,7 +67,7 @@ class QRImagick extends QROutputAbstract{
|
||||
*
|
||||
* @return string|\Imagick
|
||||
*/
|
||||
public function dump(string $file = null){
|
||||
public function dump(?string $file = null){
|
||||
$file ??= $this->options->cachefile;
|
||||
$this->imagick = new Imagick;
|
||||
|
||||
|
||||
@@ -53,7 +53,7 @@ class QRMarkup extends QROutputAbstract{
|
||||
/**
|
||||
* HTML output
|
||||
*/
|
||||
protected function html(string $file = null):string{
|
||||
protected function html(?string $file = null):string{
|
||||
|
||||
$html = empty($this->options->cssClass)
|
||||
? '<div>'
|
||||
@@ -74,9 +74,11 @@ class QRMarkup extends QROutputAbstract{
|
||||
$html .= '</div>'.$this->options->eol;
|
||||
|
||||
if($file !== null){
|
||||
return '<!DOCTYPE html>'.
|
||||
'<head><meta charset="UTF-8"><title>QR Code</title></head>'.
|
||||
'<body>'.$this->options->eol.$html.'</body>';
|
||||
/** @noinspection HtmlRequiredLangAttribute */
|
||||
return sprintf(
|
||||
'<!DOCTYPE html><html><head><meta charset="UTF-8"><title>QR Code</title></head><body>%s</body></html>',
|
||||
$this->options->eol.$html
|
||||
);
|
||||
}
|
||||
|
||||
return $html;
|
||||
@@ -87,7 +89,7 @@ class QRMarkup extends QROutputAbstract{
|
||||
*
|
||||
* @see https://github.com/codemasher/php-qrcode/pull/5
|
||||
*/
|
||||
protected function svg(string $file = null):string{
|
||||
protected function svg(?string $file = null):string{
|
||||
$matrix = $this->matrix->matrix();
|
||||
|
||||
$svg = sprintf($this->svgHeader, $this->options->cssClass, $this->options->svgViewBoxSize ?? $this->moduleCount)
|
||||
|
||||
@@ -12,7 +12,8 @@
|
||||
|
||||
namespace chillerlan\QRCode\Output;
|
||||
|
||||
use chillerlan\QRCode\{Data\QRMatrix, QRCode};
|
||||
use chillerlan\QRCode\QRCode;
|
||||
use chillerlan\QRCode\Data\QRMatrix;
|
||||
use chillerlan\Settings\SettingsContainerInterface;
|
||||
|
||||
use function call_user_func_array, dirname, file_put_contents, get_called_class, in_array, is_writable, sprintf;
|
||||
@@ -112,7 +113,7 @@ abstract class QROutputAbstract implements QROutputInterface{
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function dump(string $file = null){
|
||||
public function dump(?string $file = null){
|
||||
$file ??= $this->options->cachefile;
|
||||
|
||||
// call the built-in output method with the optional file path as parameter
|
||||
|
||||
@@ -19,29 +19,32 @@ use chillerlan\QRCode\Data\QRMatrix;
|
||||
*/
|
||||
interface QROutputInterface{
|
||||
|
||||
const DEFAULT_MODULE_VALUES = [
|
||||
public const DEFAULT_MODULE_VALUES = [
|
||||
// light
|
||||
QRMatrix::M_NULL => false, // 0
|
||||
QRMatrix::M_DATA => false, // 4
|
||||
QRMatrix::M_FINDER => false, // 6
|
||||
QRMatrix::M_SEPARATOR => false, // 8
|
||||
QRMatrix::M_ALIGNMENT => false, // 10
|
||||
QRMatrix::M_TIMING => false, // 12
|
||||
QRMatrix::M_FORMAT => false, // 14
|
||||
QRMatrix::M_VERSION => false, // 16
|
||||
QRMatrix::M_QUIETZONE => false, // 18
|
||||
QRMatrix::M_LOGO => false, // 20
|
||||
QRMatrix::M_TEST => false, // 255
|
||||
QRMatrix::M_NULL => false,
|
||||
QRMatrix::M_DARKMODULE_LIGHT => false,
|
||||
QRMatrix::M_DATA => false,
|
||||
QRMatrix::M_FINDER => false,
|
||||
QRMatrix::M_SEPARATOR => false,
|
||||
QRMatrix::M_ALIGNMENT => false,
|
||||
QRMatrix::M_TIMING => false,
|
||||
QRMatrix::M_FORMAT => false,
|
||||
QRMatrix::M_VERSION => false,
|
||||
QRMatrix::M_QUIETZONE => false,
|
||||
QRMatrix::M_LOGO => false,
|
||||
QRMatrix::M_FINDER_DOT_LIGHT => false,
|
||||
// dark
|
||||
QRMatrix::M_DARKMODULE << 8 => true, // 512
|
||||
QRMatrix::M_DATA << 8 => true, // 1024
|
||||
QRMatrix::M_FINDER << 8 => true, // 1536
|
||||
QRMatrix::M_ALIGNMENT << 8 => true, // 2560
|
||||
QRMatrix::M_TIMING << 8 => true, // 3072
|
||||
QRMatrix::M_FORMAT << 8 => true, // 3584
|
||||
QRMatrix::M_VERSION << 8 => true, // 4096
|
||||
QRMatrix::M_FINDER_DOT << 8 => true, // 5632
|
||||
QRMatrix::M_TEST << 8 => true, // 65280
|
||||
QRMatrix::M_DARKMODULE => true,
|
||||
QRMatrix::M_DATA_DARK => true,
|
||||
QRMatrix::M_FINDER_DARK => true,
|
||||
QRMatrix::M_SEPARATOR_DARK => true,
|
||||
QRMatrix::M_ALIGNMENT_DARK => true,
|
||||
QRMatrix::M_TIMING_DARK => true,
|
||||
QRMatrix::M_FORMAT_DARK => true,
|
||||
QRMatrix::M_VERSION_DARK => true,
|
||||
QRMatrix::M_QUIETZONE_DARK => true,
|
||||
QRMatrix::M_LOGO_DARK => true,
|
||||
QRMatrix::M_FINDER_DOT => true,
|
||||
];
|
||||
|
||||
/**
|
||||
@@ -49,6 +52,6 @@ interface QROutputInterface{
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function dump(string $file = null);
|
||||
public function dump(?string $file = null);
|
||||
|
||||
}
|
||||
|
||||
@@ -50,7 +50,7 @@ class QRString extends QROutputAbstract{
|
||||
/**
|
||||
* string output
|
||||
*/
|
||||
protected function text(string $file = null):string{
|
||||
protected function text(?string $file = null):string{
|
||||
$str = [];
|
||||
|
||||
foreach($this->matrix->matrix() as $row){
|
||||
@@ -69,7 +69,7 @@ class QRString extends QROutputAbstract{
|
||||
/**
|
||||
* JSON output
|
||||
*/
|
||||
protected function json(string $file = null):string{
|
||||
protected function json(?string $file = null):string{
|
||||
return json_encode($this->matrix->matrix());
|
||||
}
|
||||
|
||||
|
||||
12
vendor/chillerlan/php-qrcode/src/QRCode.php
vendored
12
vendor/chillerlan/php-qrcode/src/QRCode.php
vendored
@@ -117,23 +117,23 @@ class QRCode{
|
||||
* @var string[][]
|
||||
*/
|
||||
public const OUTPUT_MODES = [
|
||||
QRMarkup::class => [
|
||||
QRMarkup::class => [
|
||||
self::OUTPUT_MARKUP_SVG,
|
||||
self::OUTPUT_MARKUP_HTML,
|
||||
],
|
||||
QRImage::class => [
|
||||
QRImage::class => [
|
||||
self::OUTPUT_IMAGE_PNG,
|
||||
self::OUTPUT_IMAGE_GIF,
|
||||
self::OUTPUT_IMAGE_JPG,
|
||||
],
|
||||
QRString::class => [
|
||||
QRString::class => [
|
||||
self::OUTPUT_STRING_JSON,
|
||||
self::OUTPUT_STRING_TEXT,
|
||||
],
|
||||
QRImagick::class => [
|
||||
self::OUTPUT_IMAGICK,
|
||||
],
|
||||
QRFpdf::class => [
|
||||
QRFpdf::class => [
|
||||
self::OUTPUT_FPDF
|
||||
]
|
||||
];
|
||||
@@ -167,7 +167,7 @@ class QRCode{
|
||||
*
|
||||
* Sets the options instance, determines the current mb-encoding and sets it to UTF-8
|
||||
*/
|
||||
public function __construct(SettingsContainerInterface $options = null){
|
||||
public function __construct(?SettingsContainerInterface $options = null){
|
||||
$this->options = $options ?? new QROptions;
|
||||
}
|
||||
|
||||
@@ -176,7 +176,7 @@ class QRCode{
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function render(string $data, string $file = null){
|
||||
public function render(string $data, ?string $file = null){
|
||||
return $this->initOutputInterface($data)->dump($file);
|
||||
}
|
||||
|
||||
|
||||
@@ -140,12 +140,12 @@ trait QROptionsTrait{
|
||||
/**
|
||||
* string substitute for dark
|
||||
*/
|
||||
protected string $textDark = '🔴';
|
||||
protected string $textDark = '██';
|
||||
|
||||
/**
|
||||
* string substitute for light
|
||||
*/
|
||||
protected string $textLight = '⭕';
|
||||
protected string $textLight = '░░';
|
||||
|
||||
/**
|
||||
* markup substitute for dark (CSS value)
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
ko_fi: codemasher
|
||||
custom: "https://www.paypal.com/donate?hosted_button_id=WLYUNAT9ZTJZ4"
|
||||
@@ -1,105 +0,0 @@
|
||||
# https://help.github.com/en/categories/automating-your-workflow-with-github-actions
|
||||
# https://github.com/sebastianbergmann/phpunit/blob/master/.github/workflows/ci.yml
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
|
||||
|
||||
name: "CI"
|
||||
|
||||
jobs:
|
||||
|
||||
static-code-analysis:
|
||||
name: "Static Code Analysis"
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
env:
|
||||
PHAN_ALLOW_XDEBUG: 0
|
||||
PHAN_DISABLE_XDEBUG_WARN: 1
|
||||
|
||||
steps:
|
||||
- name: "Checkout"
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: "Install PHP"
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: "7.4"
|
||||
tools: pecl
|
||||
coverage: none
|
||||
extensions: ast, json
|
||||
|
||||
- name: "Update dependencies with composer"
|
||||
run: composer update --no-interaction --no-ansi --no-progress --no-suggest
|
||||
|
||||
- name: "Run phan"
|
||||
run: php vendor/bin/phan
|
||||
|
||||
build-docs:
|
||||
name: "Build and publish Docs"
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: "Checkout sources"
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: "Install PHP"
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: "8.1"
|
||||
coverage: none
|
||||
tools: phpDocumentor
|
||||
extensions: json
|
||||
|
||||
- name: "Build Docs"
|
||||
run: phpdoc --config=phpdoc.xml
|
||||
|
||||
- name: "Publish Docs to gh-pages"
|
||||
uses: JamesIves/github-pages-deploy-action@v4.3.4
|
||||
with:
|
||||
branch: gh-pages
|
||||
folder: docs
|
||||
clean: true
|
||||
|
||||
tests:
|
||||
name: "Unit Tests"
|
||||
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os:
|
||||
- ubuntu-latest
|
||||
- windows-latest
|
||||
php-version:
|
||||
- "7.4"
|
||||
- "8.0"
|
||||
- "8.1"
|
||||
|
||||
steps:
|
||||
- name: "Checkout"
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: "Install PHP with extensions"
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: ${{ matrix.php-version }}
|
||||
coverage: pcov
|
||||
extensions: json
|
||||
|
||||
- name: "Install dependencies with composer"
|
||||
run: composer update --no-ansi --no-interaction --no-progress --no-suggest
|
||||
|
||||
- name: "Run tests with phpunit"
|
||||
run: php vendor/phpunit/phpunit/phpunit --configuration=phpunit.xml
|
||||
|
||||
- name: "Send code coverage report to Codecov.io"
|
||||
uses: codecov/codecov-action@v3
|
||||
@@ -1,4 +0,0 @@
|
||||
/.build
|
||||
/.idea
|
||||
/vendor
|
||||
composer.lock
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user