acg-faka Documentation

个人发卡源码,发卡系统,二次元发卡系统,二次元发卡源码,发卡程序,动漫发卡,PHP发卡源码,异次元发卡

5,853 stars PHP PHP 37 files · ~34,596 tokens
RAW Doc

Docker & Self-Hosted Deployment Verified OCI

Deploy acg-faka on any server, homelab, or cloud container platform.

1-Click Terminal Command
bash (docker run)
docker run -d --name acg-faka -p 8080:8080 --restart always acg-faka:local
Configured Services & Ports
⚙️ secrets-init
image: mysql:5.7
⚙️ app
image: acg-faka:local
🔌 Ports: ${ACG_HTTP_PORT:-8080}:80
⚙️ mysql
image: mysql:5.7
⚙️ redis
image: redis:7.2-alpine
docker-compose.yml
yaml (docker-compose.yml)
# acg-faka 一键部署。
#
#   docker compose up -d
#
# 就这一条命令。不需要 .env,不需要改任何文件,不需要想数据库密码 ——
# 内置 MySQL 的密码首次启动时随机生成并保存在密钥卷里,安装向导会自动读到,
# 打开 http://localhost:8080 直接开始装。

services:
  # 首次启动生成随机数据库密码;已存在则原样保留。
  # 借用 mysql 镜像跑一个 shell,省掉再拉一个 busybox。
  secrets-init:
    image: mysql:5.7
    platform: linux/amd64
    container_name: acg-faka-secrets-init
    restart: "no"
    entrypoint: ["/bin/sh", "/secrets-init.sh"]
    volumes:
      - ./docker/secrets-init.sh:/secrets-init.sh:ro
      - acg_secrets:/secrets

  app:
    build:
      context: .
      dockerfile: Dockerfile
    image: acg-faka:local
    container_name: acg-faka-app
    restart: unless-stopped
    depends_on:
      mysql:
        condition: service_healthy
      redis:
        condition: service_started
    ports:
      - "${ACG_HTTP_PORT:-8080}:80"
    environment:
      TZ: Asia/Shanghai
      # 安装向导据此自动填好内置数据库的连接信息,用户不用输入任何东西
      ACG_DB_HOST: mysql
      ACG_DB_PORT: "3306"
      ACG_DB_DATABASE: acg_faka
      ACG_DB_USERNAME: acg
      ACG_DB_PASSWORD_FILE: /secrets/mysql_app
      ACG_DB_PREFIX: acg_
      # 有 redis 就把会话放 redis;不设这个变量时 entrypoint 会自动退回文件会话
      ACG_REDIS_HOST: redis
      ACG_REDIS_PORT: "6379"
    volumes:
      - acg_secrets:/secrets:ro
      # 镜像里站点的可写目录(配置/运行时/上传/插件/支付/模板/安装锁)都软链到 /data,
      # 挂这一个卷就全保住了。别再按老结构逐个挂到 /var/www/html/... —— 那些路径
      # 现在是软链,挂上去会把软链盖掉,站点起不来。
      - acg_data:/data

  mysql:
    image: mysql:5.7
    # MySQL 5.7 官方只发 amd64 镜像。ARM 机器(Apple Silicon / Ampere / Graviton)
    # 会通过 qemu 模拟运行,能跑但偏慢;想要原生性能就把这两行换成 mariadb:10.6。
    platform: linux/amd64
    container_name: acg-faka-mysql
    restart: unless-stopped
    depends_on:
      secrets-init:
        condition: service_completed_successfully
    environment:
      MYSQL_ROOT_PASSWORD_FILE: /secrets/mysql_root
      MYSQL_DATABASE: acg_faka
      MYSQL_USER: acg
      MYSQL_PASSWORD_FILE: /secrets/mysql_app
      TZ: Asia/Shanghai
    command:
      - --character-set-server=utf8mb4
      - --collation-server=utf8mb4_general_ci
      - --innodb-buffer-pool-size=256M
      - --max-connections=200
    volumes:
      - acg_secrets:/secrets:ro
      - acg_mysql:/var/lib/mysql
    healthcheck:
      test: ["CMD-SHELL", "mysqladmin ping -h 127.0.0.1 -uroot -p\"$$(cat /secrets/mysql_root)\" --silent"]
      interval: 5s
      timeout: 5s
      retries: 40
      start_period: 30s

  redis:
    image: redis:7.2-alpine
    container_name: acg-faka-redis
    restart: unless-stopped
    command: ["redis-server", "--appendonly", "yes"]
    volumes:
      - acg_redis:/data
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 10s
      timeout: 3s
      retries: 5

volumes:
  acg_secrets:
  acg_data:
  acg_mysql:
  acg_redis:

Technical Documentation: lizhipay/acg-faka

ℹ️ Provenance: Multi-Tier Ingestion · CodeWiki Reference

Overview (`README.md`)

法律声明

本商城程序基于 MIT 协议开源,并且完全免费。该程序的初衷是为开发者提供学习和研究的机会。未取得合法资质,严禁将本程序用于任何商业用途,尤其是禁止利用本程序搭建平台进行商品销售。

用户在使用或学习本程序时,必须严格遵守法律法规。我们提倡依法行事,尊重法律,坚守法律,避免对社会产生不良影响。

使用本程序即表示您已充分理解并同意本法律声明的所有内容。

广告

🚀 ARM AI — GPT / Claude / Gemini / Grok Token 服务平台,超低倍率、余额长期有效并支持无理由退款。立即体验:https://ai.arm.moe/

在线演示

地址 账号 密码
前台 https://demo.faka.wiki 为了明天美好而战斗 123456
后台 https://demo.faka.wiki/admin [email protected] 123456

功能一览

  • 商品与发货:卡密自动发货、手动发货(可开启「付款即发货」)、卡密预选(买家自选卡号,可单独加价)、种类与 SKU 规格、批发价、限时秒杀、优惠券、限购、强制登录购买、自定义下单控件、邮件通知。
  • 价格与会员:游客价与会员价分开设置,会员等级、商户等级完全自定义,每个商品都能按会员等级单独定价。
  • 支付:支付网关全部插件化,几乎任何支付渠道都能接入;内置余额支付与在线充值。
  • 分站:会员可以开通自己的分站并绑定独立域名,自行上架商品,也可以代售主站商品。
  • 推广分成:会员等级即代理等级,推广人赚取买家实付金额与自身等级价之间的差价。
  • 店铺对接:在后台直接对接其他店铺的商品,用余额自动进货、自动发货。
  • 应用商店:在后台安装插件与模板;核心程序可一键在线升级。
  • 多语言与多币种:内置简体中文、繁体中文、English、日本語,可自定义站点货币与汇率。
  • 安全:两步验证与通行密钥(Passkey)登录、后台安全入口、内容安全策略(CSP)等多层防护。
  • 界面:PC 与手机端完整适配,应用商店里有多套风格各异的模板。
  • 二次开发:80 多个 Hook 埋点,插件可以接管下单、发货、支付等流程。比如:游戏道具购买后即时发到玩家背包、商业软件自动授权与余额充值、论坛 / 社区 VIP 自动开通。

安装

方式一:Docker(推荐)

bash
docker run -d --name faka -p 80:80 -v acg_data:/data --restart unless-stopped ghcr.io/lizhipay/acg-faka:latest

镜像自带 MariaDB 与 Redis,启动后打开 http://服务器IP 即可进入安装向导,数据库信息已经自动填好。站点的全部数据都在 /data 卷里,务必挂载。需要使用独立的 MySQL 时,请参考 Docker 安装文档。

方式二:宝塔面板 / 手动安装

项目 要求
PHP 8.0 及以上(推荐 8.2)
MySQL 5.7 及以上(MariaDB 10.3+ 亦可)
PHP 扩展 gd、curl、pdo、pdo_mysql、date、json、session、zip、bcmath
伪静态 必须配置,见下方
  1. 获取源码:composer create-project lizhipay/acg-faka,或从 GitHub、faka.wiki/download.php 下载压缩包。

  2. 配置伪静态:Apache 无需配置,根目录已自带 .htaccess;Nginx 请把下面整段粘进站点配置(宝塔:网站 → 伪静态)。

    nginx
    if ($uri ~* "^/(?!(?-i:index\.php)(/|$)).*\.php(/|$)")             { return 404; }
    
    location ~* ^/(runtime|kernel|config|vendor)/                { return 404; }
    location ~  (^|/)(runtime|\.acgcache)(/|$)                   { return 404; }
    location ~  /\.(?!well-known)                                { return 404; }
    location ~* \.(log|sql|sqlite|db|db-wal|db-shm|bak|old|save|orig|swp|swo|tmp|ini|lock|key|pem|crt|cer|der|p12|pfx|p8|keystore|jks|asc|gpg|ppk|env|secret)$  { return 404; }
    location ~* (~|composer\.(json|lock)|package(-lock)?\.json)$ { return 404; }
    location / {
        try_files $uri $uri/ /index.php?s=$uri&$args;
    }

    请整段复制,不要只抄最后的 location /:前面几条负责挡住日志、配置、密钥等不该被访问的文件。IIS 规则见伪静态文档。

  3. 确认 config、runtime、kernel/Install、assets/cache 目录可写,然后访问网站首页,按安装向导完成安装。

  4. 后台地址:https://你的域名/admin

更详细的步骤(含 Windows)见安装文档。

升级

后台左下角显示当前版本号,点击即可检查新版本并一键在线升级,Docker 部署同样适用。升级前请先备份数据库;手动升级的方法见升级文档。

二次开发

插件、支付插件、Hook 与 API 对接的说明见开发者文档。

交流与反馈

开源协议

MIT


Overview (`docker/README.md`)

Docker 部署

最简单:一个容器

bash
docker run -d --name acg-faka -p 80:80 -v acg_data:/data --restart unless-stopped ghcr.io/lizhipay/acg-faka:latest

就这一条。 镜像自带 MariaDB 和 Redis,数据库密码首次启动随机生成,
打开 http://服务器IP 直接进安装向导 —— 数据库那一步已经替你填好,只需要设个管理员账号。

宝塔 / 1Panel 的「创建容器」里也是同样三件事:镜像填 ghcr.io/lizhipay/acg-faka:latest、
端口映射 主机端口 → 容器 80、目录映射一个卷到 /data。

⚠️ 容器内部端口是 80,不是 8080。映射错了浏览器打不开。

⚠️ /data 一定要挂出来。站点的数据库、配置、上传文件、插件、模板全在里面,
不挂的话容器一删数据就没了。

要独立的 MySQL / Redis:用 compose

bash
docker compose up -d

同样不需要 .env、不需要改文件。这种方式下内置的 MariaDB/Redis 不会启动,
app 容器只跑 nginx + php-fpm,数据库走独立的 mysql 服务。

改端口:ACG_HTTP_PORT=8081 docker compose up -d

这套编排有什么

服务 镜像 说明
app 本仓库构建 nginx + php-fpm 8.2(+ 单容器模式下的 MariaDB/Redis),supervisord 托管,对外只开 80
mysql mysql:5.7 只在内网可达,不往宿主机发布端口
redis redis:7.2-alpine PHP 会话存储(acg_sess: 前缀,db 1)
secrets-init 一次性任务 首次启动生成随机数据库密码,之后退出

密码是怎么来的

镜像里不带任何默认密码。首次 up 时 secrets-init 会往 acg_secrets 卷里写两串
32 位随机密码(root 一串、应用一串,权限 600),MySQL 通过 MYSQL_*_PASSWORD_FILE
读它,安装向导则由服务端读出来直接用。

密码不会渲染进安装页面的 HTML —— 页面把密码栏留空、提交时带一个
use_builtin=1 标记,服务端自己去环境变量里取。

要自己看一眼的话:

bash
docker compose exec mysql cat /secrets/mysql_root

想用外部数据库

安装向导第二步点「改用其它数据库」,手填即可,内置的那套就不会被用到。
也可以直接把 compose 里的 mysql 服务和 ACG_DB_* 环境变量删掉。

为什么是 nginx 而不是 Apache

整个程序只有 index.php 一个 web 入口,其余请求都靠 ?s= 路由。所以 nginx 配置里
只放行了它一个,其它 .php 一律返回 404 —— 上传目录里就算真被塞进一个 .php
也执行不了。config/、kernel/、runtime/、vendor/ 和点开头的文件同样直接 404。

伪静态规则随镜像发布(等价于仓库里的 .htaccess),用户不需要配置任何东西。

反向代理(Caddy / Traefik / CDN / 宝塔)放在前面时,X-Forwarded-Proto 和
X-Forwarded-For 会被正确转成 $_SERVER['HTTPS'] 与真实来访 IP —— 只信任私有网段,
公网伪造的头不生效。

线程管理器插件

在应用商店装好插件后,进容器执行一次(只需一次,二进制会落在数据卷里):

bash
docker compose exec app ./app/Plugin/ThreadManager/service.sh install
# 单容器:docker exec -it acg-faka ./app/Plugin/ThreadManager/service.sh install

之后不用再管 —— 容器每次启动都会自动把它的守护进程交给 supervisord 拉起,
不需要 service.sh start。

GitHub 直连不稳导致下载不完整时,脚本会自动换镜像源重试;还是不行就手动指定:
TM_MIRRORS="https://ghfast.top/" ./app/Plugin/ThreadManager/service.sh install

线程管理器(如果你装了)

镜像会自动接管它:容器启动时若检测到 app/Plugin/ThreadManager/swoole-cli,
就把守护进程注册成 supervisord 的程序,和 nginx / php-fpm 一个待遇 ——
容器起来自动拉起、崩溃自动重启、docker stop 时按 stop_timeout 优雅收尾。

注意:托管是在容器启动时登记的,所以插件装好、二进制下完之后要
重启一次容器才会生效(docker restart <容器名>)。在那之前 service.sh start
起的进程照常能用,只是活不过容器重建。

el9 系宿主机的 xz 坑

在 RHEL 9 / AlmaLinux 9 / Rocky 9(内核 5.14.x.el9)上,容器里任何 xz 操作都会报:

text
xz: Failed to enable the sandbox

原因是这类内核回移 Landlock 时版本号谎报(landlock_create_ruleset 查询返回 ABI 6,
实际建规则集却 EINVAL),而 xz 5.6+ 把沙箱失败当致命错误。跟下载的包无关,
包是好的。线程管理器 1.0.7 起会在这种情况下自动改用 python3 的 lzma 解包,无需干预。

已知限制

  • 默认 PHP 8.2(Debian bookworm,仍在支持期)。需要贴合旧线上环境时可以降版本:

    bash
    docker compose build --build-arg PHP_VERSION=8.0 app

    ⚠ 但 PHP 8.0 / 8.1 已停止安全维护,它们的 Debian bullseye 底座也整体进了归档 ——
    构建时会自动改用 archive.debian.org,代价是镜像里的系统包(包括 nginx、openssl)
    拿不到任何新的安全更新。挂公网的站点不建议这么用。

  • MySQL 5.7 官方只发 amd64 镜像。ARM 机器(Apple Silicon / Ampere / Graviton)
    会通过 qemu 模拟运行 —— 能跑,但导入数据那一步明显偏慢。想要原生性能就把
    compose 里的 mysql 服务换成 mariadb:10.6 并删掉 platform: 那行。

持久化

站点里所有会被写入的目录(配置、运行时、上传、插件、支付、模板、安装锁)在镜像里
都软链到 /data,挂这一个卷就全保住了。单容器模式下数据库和 Redis 的数据也在
/data/mysql、/data/redis。

compose 方式下是 acg_data(站点)+ acg_mysql + acg_redis + acg_secrets(密码)。

常用命令

bash
docker compose logs -f app          # 看日志(访问日志只由 nginx 出,不重复)
docker compose restart app          # 重启
docker compose down                 # 停止(数据保留)
docker compose down -v              # 停止并清空所有数据,回到全新状态

Overview (`vendor/doctrine/inflector/README.md`)

Doctrine Inflector

Doctrine Inflector is a small library that can perform string manipulations
with regard to uppercase/lowercase and singular/plural forms of words.



Overview (`vendor/ezyang/htmlpurifier/README.md`)

HTML Purifier [](https://github.com/ezyang/htmlpurifier/actions/workflows/ci.yml)

HTML Purifier is an HTML filtering solution that uses a unique combination
of robust whitelists and aggressive parsing to ensure that not only are
XSS attacks thwarted, but the resulting HTML is standards compliant.

HTML Purifier is oriented towards richly formatted documents from
untrusted sources that require CSS and a full tag-set. This library can
be configured to accept a more restrictive set of tags, but it won't be
as efficient as more bare-bones parsers. It will, however, do the job
right, which may be more important.

Places to go:

  • See INSTALL for a quick installation guide
  • See docs/ for developer-oriented documentation, code examples and
    an in-depth installation guide.
  • See WYSIWYG for information on editors like TinyMCE and FCKeditor

HTML Purifier can be found on the web at: http://htmlpurifier.org/

Installation

Package available on Composer.

If you're using Composer to manage dependencies, you can use

text
$ composer require ezyang/htmlpurifier

Overview (`vendor/firebase/php-jwt/README.md`)



PHP-JWT

A simple library to encode and decode JSON Web Tokens (JWT) in PHP, conforming to RFC 7519.

Installation

Use composer to manage your dependencies and download PHP-JWT:

bash
composer require firebase/php-jwt

Optionally, install the paragonie/sodium_compat package from composer if your
php env does not have libsodium installed:

bash
composer require paragonie/sodium_compat

Example

php
use Firebase\JWT\JWT;
use Firebase\JWT\Key;

$key = 'example_key';
$payload = [
    'iss' => 'http://example.org',
    'aud' => 'http://example.com',
    'iat' => 1356999524,
    'nbf' => 1357000000
];

/**
 * IMPORTANT:
 * You must specify supported algorithms for your application. See
 * https://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-40
 * for a list of spec-compliant algorithms.
 */
$jwt = JWT::encode($payload, $key, 'HS256');
$decoded = JWT::decode($jwt, new Key($key, 'HS256'));
print_r($decoded);

// Pass a stdClass in as the third parameter to get the decoded header values
$headers = new stdClass();
$decoded = JWT::decode($jwt, new Key($key, 'HS256'), $headers);
print_r($headers);

/*
 NOTE: This will now be an object instead of an associative array. To get
 an associative array, you will need to cast it as such:
*/

$decoded_array = (array) $decoded;

/**
 * You can add a leeway to account for when there is a clock skew times between
 * the signing and verifying servers. It is recommended that this leeway should
 * not be bigger than a few minutes.
 *
 * Source: http://self-issued.info/docs/draft-ietf-oauth-json-web-token.html#nbfDef
 */
JWT::$leeway = 60; // $leeway in seconds
$decoded = JWT::decode($jwt, new Key($key, 'HS256'));

Example encode/decode headers

Decoding the JWT headers without verifying the JWT first is NOT recommended, and is not supported by
this library. This is because without verifying the JWT, the header values could have been tampered with.
Any value pulled from an unverified header should be treated as if it could be any string sent in from an
attacker. If this is something you still want to do in your application for whatever reason, it's possible to
decode the header values manually simply by calling json_decode and base64_decode on the JWT
header part:

php
use Firebase\JWT\JWT;

$key = 'example_key';
$payload = [
    'iss' => 'http://example.org',
    'aud' => 'http://example.com',
    'iat' => 1356999524,
    'nbf' => 1357000000
];

$headers = [
    'x-forwarded-for' => 'www.google.com'
];

// Encode headers in the JWT string
$jwt = JWT::encode($payload, $key, 'HS256', null, $headers);

// Decode headers from the JWT string WITHOUT validation
// **IMPORTANT**: This operation is vulnerable to attacks, as the JWT has not yet been verified.
// These headers could be any value sent by an attacker.
list($headersB64, $payloadB64, $sig) = explode('.', $jwt);
$decoded = json_decode(base64_decode($headersB64), true);

print_r($decoded);

Example with RS256 (openssl)

text
/* Detailed source-code truncated for AI context efficiency. */

Example with a passphrase

php
use Firebase\JWT\JWT;
use Firebase\JWT\Key;

// Your passphrase
$passphrase = '[YOUR_PASSPHRASE]';

// Your private key file with passphrase
// Can be generated with "ssh-keygen -t rsa -m pem"
$privateKeyFile = '/path/to/key-with-passphrase.pem';

// Create a private key of type "resource"
$privateKey = openssl_pkey_get_private(
    file_get_contents($privateKeyFile),
    $passphrase
);

$payload = [
    'iss' => 'example.org',
    'aud' => 'example.com',
    'iat' => 1356999524,
    'nbf' => 1357000000
];

$jwt = JWT::encode($payload, $privateKey, 'RS256');
echo "Encode:\n" . print_r($jwt, true) . "\n";

// Get public key from the private key, or pull from from a file.
$publicKey = openssl_pkey_get_details($privateKey)['key'];

$decoded = JWT::decode($jwt, new Key($publicKey, 'RS256'));
echo "Decode:\n" . print_r((array) $decoded, true) . "\n";

Example with EdDSA (libsodium and Ed25519 signature)

php
use Firebase\JWT\JWT;
use Firebase\JWT\Key;

// Public and private keys are expected to be Base64 encoded. The last
// non-empty line is used so that keys can be generated with
// sodium_crypto_sign_keypair(). The secret keys generated by other tools may
// need to be adjusted to match the input expected by libsodium.

$keyPair = sodium_crypto_sign_keypair();

$privateKey = base64_encode(sodium_crypto_sign_secretkey($keyPair));

$publicKey = base64_encode(sodium_crypto_sign_publickey($keyPair));

$payload = [
    'iss' => 'example.org',
    'aud' => 'example.com',
    'iat' => 1356999524,
    'nbf' => 1357000000
];

$jwt = JWT::encode($payload, $privateKey, 'EdDSA');
echo "Encode:\n" . print_r($jwt, true) . "\n";

$decoded = JWT::decode($jwt, new Key($publicKey, 'EdDSA'));
echo "Decode:\n" . print_r((array) $decoded, true) . "\n";

Example with multiple keys

php
use Firebase\JWT\JWT;
use Firebase\JWT\Key;

// Example RSA keys from previous example
// $privateKey1 = '...';
// $publicKey1 = '...';

// Example EdDSA keys from previous example
// $privateKey2 = '...';
// $publicKey2 = '...';

$payload = [
    'iss' => 'example.org',
    'aud' => 'example.com',
    'iat' => 1356999524,
    'nbf' => 1357000000
];

$jwt1 = JWT::encode($payload, $privateKey1, 'RS256', 'kid1');
$jwt2 = JWT::encode($payload, $privateKey2, 'EdDSA', 'kid2');
echo "Encode 1:\n" . print_r($jwt1, true) . "\n";
echo "Encode 2:\n" . print_r($jwt2, true) . "\n";

$keys = [
    'kid1' => new Key($publicKey1, 'RS256'),
    'kid2' => new Key($publicKey2, 'EdDSA'),
];

$decoded1 = JWT::decode($jwt1, $keys);
$decoded2 = JWT::decode($jwt2, $keys);

echo "Decode 1:\n" . print_r((array) $decoded1, true) . "\n";
echo "Decode 2:\n" . print_r((array) $decoded2, true) . "\n";

Using JWKs

php
use Firebase\JWT\JWK;
use Firebase\JWT\JWT;

// Set of keys. The "keys" key is required. For example, the JSON response to
// this endpoint: https://www.gstatic.com/iap/verify/public_key-jwk
$jwks = ['keys' => []];

// JWK::parseKeySet($jwks) returns an associative array of **kid** to Firebase\JWT\Key
// objects. Pass this as the second parameter to JWT::decode.
JWT::decode($jwt, JWK::parseKeySet($jwks));

Using Cached Key Sets

The CachedKeySet class can be used to fetch and cache JWKS (JSON Web Key Sets) from a public URI.
This has the following advantages:

  1. The results are cached for performance.
  2. If an unrecognized key is requested, the cache is refreshed, to accomodate for key rotation.
  3. If rate limiting is enabled, the JWKS URI will not make more than 10 requests a second.
php
use Firebase\JWT\CachedKeySet;
use Firebase\JWT\JWT;

// The URI for the JWKS you wish to cache the results from
$jwksUri = 'https://www.gstatic.com/iap/verify/public_key-jwk';

// Create an HTTP client (can be any PSR-7 compatible HTTP client)
$httpClient = new GuzzleHttp\Client();

// Create an HTTP request factory (can be any PSR-17 compatible HTTP request factory)
$httpFactory = new GuzzleHttp\Psr\HttpFactory();

// Create a cache item pool (can be any PSR-6 compatible cache item pool)
$cacheItemPool = Phpfastcache\CacheManager::getInstance('files');

$keySet = new CachedKeySet(
    $jwksUri,
    $httpClient,
    $httpFactory,
    $cacheItemPool,
    null, // $expiresAfter int seconds to set the JWKS to expire
    true  // $rateLimit    true to enable rate limit of 10 RPS on lookup of invalid keys
);

$jwt = 'eyJhbGci...'; // Some JWT signed by a key from the $jwkUri above
$decoded = JWT::decode($jwt, $keySet);

Miscellaneous

Exception Handling

When a call to JWT::decode is invalid, it will throw one of the following exceptions:

php
use Firebase\JWT\JWT;
use Firebase\JWT\SignatureInvalidException;
use Firebase\JWT\BeforeValidException;
use Firebase\JWT\ExpiredException;
use DomainException;
use InvalidArgumentException;
use UnexpectedValueException;

try {
    $decoded = JWT::decode($jwt, $keys);
} catch (InvalidArgumentException $e) {
    // provided key/key-array is empty or malformed.
} catch (DomainException $e) {
    // provided algorithm is unsupported OR
    // provided key is invalid OR
    // unknown error thrown in openSSL or libsodium OR
    // libsodium is required but not available.
} catch (SignatureInvalidException $e) {
    // provided JWT signature verification failed.
} catch (BeforeValidException $e) {
    // provided JWT is trying to be used before "nbf" claim OR
    // provided JWT is trying to be used before "iat" claim.
} catch (ExpiredException $e) {
    // provided JWT is trying to be used after "exp" claim.
} catch (UnexpectedValueException $e) {
    // provided JWT is malformed OR
    // provided JWT is missing an algorithm / using an unsupported algorithm OR
    // provided JWT algorithm does not match provided key OR
    // provided key ID in key/key-array is empty or invalid.
}

All exceptions in the Firebase\JWT namespace extend UnexpectedValueException, and can be simplified
like this:

php
use Firebase\JWT\JWT;
use UnexpectedValueException;
try {
    $decoded = JWT::decode($jwt, $keys);
} catch (LogicException $e) {
    // errors having to do with environmental setup or malformed JWT Keys
} catch (UnexpectedValueException $e) {
    // errors having to do with JWT signature and claims
}

Casting to array

The return value of JWT::decode is the generic PHP object stdClass. If you'd like to handle with arrays
instead, you can do the following:

php
// return type is stdClass
$decoded = JWT::decode($jwt, $keys);

// cast to array
$decoded = json_decode(json_encode($decoded), true);

Tests

Run the tests using phpunit:

bash
$ pear install PHPUnit
$ phpunit --configuration phpunit.xml.dist
PHPUnit 3.7.10 by Sebastian Bergmann.
.....
Time: 0 seconds, Memory: 2.50Mb
OK (5 tests, 5 assertions)

New Lines in private keys

If your private key contains \n characters, be sure to wrap it in double quotes ""
and not single quotes '' in order to properly interpret the escaped characters.

License

3-Clause BSD.


Overview (`vendor/guzzlehttp/guzzle/README.md`)

Guzzle, PHP HTTP client



Guzzle is a PHP HTTP client that makes it easy to send HTTP requests and
trivial to integrate with web services.

  • Simple interface for building query strings, POST requests, streaming large
    uploads, streaming large downloads, using HTTP cookies, uploading JSON data,
    etc...
  • Can send both synchronous and asynchronous requests using the same interface.
  • Uses PSR-7 interfaces for requests, responses, and streams. This allows you
    to utilize other PSR-7 compatible libraries with Guzzle.
  • Supports PSR-18 allowing interoperability between other PSR-18 HTTP Clients.
  • Abstracts away the underlying HTTP transport, allowing you to write
    environment and transport agnostic code; i.e., no hard dependency on cURL,
    PHP streams, sockets, or non-blocking event loops.
  • Middleware system allows you to augment and compose client behavior.
php
$client = new \GuzzleHttp\Client();
$response = $client->request('GET', 'https://api.github.com/repos/guzzle/guzzle');

echo $response->getStatusCode(); // 200
echo $response->getHeaderLine('content-type'); // 'application/json; charset=utf8'
echo $response->getBody(); // '{"id": 1420053, "name": "guzzle", ...}'

// Send an asynchronous request.
$request = new \GuzzleHttp\Psr7\Request('GET', 'http://httpbin.org');
$promise = $client->sendAsync($request)->then(function ($response) {
    echo 'I completed! ' . $response->getBody();
});

$promise->wait();

Help and docs

We use GitHub issues only to discuss bugs and new features. For support please refer to:

Installing Guzzle

The recommended way to install Guzzle is through
Composer.

bash
composer require guzzlehttp/guzzle

Version Guidance

Version Status Packagist Namespace Repo Docs PSR-7 PHP Version
3.x EOL guzzle/guzzle Guzzle v3 v3 No >=5.3.3,<7.0
4.x EOL guzzlehttp/guzzle GuzzleHttp v4 N/A No >=5.4,<7.0
5.x EOL guzzlehttp/guzzle GuzzleHttp v5 v5 No >=5.4,<7.4
6.x Security fixes guzzlehttp/guzzle GuzzleHttp v6 v6 Yes >=5.5,<8.0
7.x Latest guzzlehttp/guzzle GuzzleHttp v7 v7 Yes >=7.2.5,<8.2

Security

If you discover a security vulnerability within this package, please send an email to [email protected]. All security vulnerabilities will be promptly addressed. Please do not disclose security-related issues publicly until a fix has been announced. Please see Security Policy for more information.

License

Guzzle is made available under the MIT License (MIT). Please see License File for more information.

For Enterprise

Available as part of the Tidelift Subscription

The maintainers of Guzzle and thousands of other packages are working with Tidelift to deliver commercial support and maintenance for the open source dependencies you use to build your applications. Save time, reduce risk, and improve code health, while paying the maintainers of the exact dependencies you use. Learn more.


Overview (`vendor/guzzlehttp/promises/README.md`)

Guzzle Promises

Promises/A+ implementation that handles promise
chaining and resolution iteratively, allowing for "infinite" promise chaining
while keeping the stack size constant. Read this blog post
for a general introduction to promises.

Features

  • Promises/A+ implementation.
  • Promise resolution and chaining is handled iteratively, allowing for
    "infinite" promise chaining.
  • Promises have a synchronous wait method.
  • Promises can be cancelled.
  • Works with any object that has a then function.
  • C# style async/await coroutine promises using
    GuzzleHttp\Promise\Coroutine::of().

Quick Start

A promise represents the eventual result of an asynchronous operation. The
primary way of interacting with a promise is through its then method, which
registers callbacks to receive either a promise's eventual value or the reason
why the promise cannot be fulfilled.

Callbacks

Callbacks are registered with the then method by providing an optional
$onFulfilled followed by an optional $onRejected function.

php
use GuzzleHttp\Promise\Promise;

$promise = new Promise();
$promise->then(
    // $onFulfilled
    function ($value) {
        echo 'The promise was fulfilled.';
    },
    // $onRejected
    function ($reason) {
        echo 'The promise was rejected.';
    }
);

Resolving a promise means that you either fulfill a promise with a value or
reject a promise with a reason. Resolving a promise triggers callbacks
registered with the promise's then method. These callbacks are triggered
only once and in the order in which they were added.

Resolving a Promise

Promises are fulfilled using the resolve($value) method. Resolving a promise
with any value other than a GuzzleHttp\Promise\RejectedPromise will trigger
all of the onFulfilled callbacks (resolving a promise with a rejected promise
will reject the promise and trigger the $onRejected callbacks).

php
use GuzzleHttp\Promise\Promise;

$promise = new Promise();
$promise
    ->then(function ($value) {
        // Return a value and don't break the chain
        return "Hello, " . $value;
    })
    // This then is executed after the first then and receives the value
    // returned from the first then.
    ->then(function ($value) {
        echo $value;
    });

// Resolving the promise triggers the $onFulfilled callbacks and outputs
// "Hello, reader."
$promise->resolve('reader.');

Promise Forwarding

Promises can be chained one after the other. Each then in the chain is a new
promise. The return value of a promise is what's forwarded to the next
promise in the chain. Returning a promise in a then callback will cause the
subsequent promises in the chain to only be fulfilled when the returned promise
has been fulfilled. The next promise in the chain will be invoked with the
resolved value of the promise.

php
use GuzzleHttp\Promise\Promise;

$promise = new Promise();
$nextPromise = new Promise();

$promise
    ->then(function ($value) use ($nextPromise) {
        echo $value;
        return $nextPromise;
    })
    ->then(function ($value) {
        echo $value;
    });

// Triggers the first callback and outputs "A"
$promise->resolve('A');
// Triggers the second callback and outputs "B"
$nextPromise->resolve('B');

Promise Rejection

When a promise is rejected, the $onRejected callbacks are invoked with the
rejection reason.

php
use GuzzleHttp\Promise\Promise;

$promise = new Promise();
$promise->then(null, function ($reason) {
    echo $reason;
});

$promise->reject('Error!');
// Outputs "Error!"

Rejection Forwarding

If an exception is thrown in an $onRejected callback, subsequent
$onRejected callbacks are invoked with the thrown exception as the reason.

php
use GuzzleHttp\Promise\Promise;

$promise = new Promise();
$promise->then(null, function ($reason) {
    throw new Exception($reason);
})->then(null, function ($reason) {
    assert($reason->getMessage() === 'Error!');
});

$promise->reject('Error!');

You can also forward a rejection down the promise chain by returning a
GuzzleHttp\Promise\RejectedPromise in either an $onFulfilled or
$onRejected callback.

php
use GuzzleHttp\Promise\Promise;
use GuzzleHttp\Promise\RejectedPromise;

$promise = new Promise();
$promise->then(null, function ($reason) {
    return new RejectedPromise($reason);
})->then(null, function ($reason) {
    assert($reason === 'Error!');
});

$promise->reject('Error!');

If an exception is not thrown in a $onRejected callback and the callback
does not return a rejected promise, downstream $onFulfilled callbacks are
invoked using the value returned from the $onRejected callback.

php
use GuzzleHttp\Promise\Promise;

$promise = new Promise();
$promise
    ->then(null, function ($reason) {
        return "It's ok";
    })
    ->then(function ($value) {
        assert($value === "It's ok");
    });

$promise->reject('Error!');

Synchronous Wait

You can synchronously force promises to complete using a promise's wait
method. When creating a promise, you can provide a wait function that is used
to synchronously force a promise to complete. When a wait function is invoked
it is expected to deliver a value to the promise or reject the promise. If the
wait function does not deliver a value, then an exception is thrown. The wait
function provided to a promise constructor is invoked when the wait function
of the promise is called.

php
$promise = new Promise(function () use (&$promise) {
    $promise->resolve('foo');
});

// Calling wait will return the value of the promise.
echo $promise->wait(); // outputs "foo"

If an exception is encountered while invoking the wait function of a promise,
the promise is rejected with the exception and the exception is thrown.

php
$promise = new Promise(function () use (&$promise) {
    throw new Exception('foo');
});

$promise->wait(); // throws the exception.

Calling wait on a promise that has been fulfilled will not trigger the wait
function. It will simply return the previously resolved value.

php
$promise = new Promise(function () { die('this is not called!'); });
$promise->resolve('foo');
echo $promise->wait(); // outputs "foo"

Calling wait on a promise that has been rejected will throw an exception. If
the rejection reason is an instance of \Exception the reason is thrown.
Otherwise, a GuzzleHttp\Promise\RejectionException is thrown and the reason
can be obtained by calling the getReason method of the exception.

php
$promise = new Promise();
$promise->reject('foo');
$promise->wait();

PHP Fatal error: Uncaught exception 'GuzzleHttp\Promise\RejectionException' with message 'The promise was rejected with value: foo'

Unwrapping a Promise

When synchronously waiting on a promise, you are joining the state of the
promise into the current state of execution (i.e., return the value of the
promise if it was fulfilled or throw an exception if it was rejected). This is
called "unwrapping" the promise. Waiting on a promise will by default unwrap
the promise state.

You can force a promise to resolve and not unwrap the state of the promise
by passing false to the first argument of the wait function:

php
$promise = new Promise();
$promise->reject('foo');
// This will not throw an exception. It simply ensures the promise has
// been resolved.
$promise->wait(false);

When unwrapping a promise, the resolved value of the promise will be waited
upon until the unwrapped value is not a promise. This means that if you resolve
promise A with a promise B and unwrap promise A, the value returned by the
wait function will be the value delivered to promise B.

Note: when you do not unwrap the promise, no value is returned.

Cancellation

You can cancel a promise that has not yet been fulfilled using the cancel()
method of a promise. When creating a promise you can provide an optional
cancel function that when invoked cancels the action of computing a resolution
of the promise.

API

Promise

When creating a promise object, you can provide an optional $waitFn and
$cancelFn. $waitFn is a function that is invoked with no arguments and is
expected to resolve the promise. $cancelFn is a function with no arguments
that is expected to cancel the computation of a promise. It is invoked when the
cancel() method of a promise is called.

php
use GuzzleHttp\Promise\Promise;

$promise = new Promise(
    function () use (&$promise) {
        $promise->resolve('waited');
    },
    function () {
        // do something that will cancel the promise computation (e.g., close
        // a socket, cancel a database query, etc...)
    }
);

assert('waited' === $promise->wait());

A promise has the following methods:

  • then(callable $onFulfilled, callable $onRejected) : PromiseInterface

    Appends fulfillment and rejection handlers to the promise, and returns a new promise resolving to the return value of the called handler.

  • otherwise(callable $onRejected) : PromiseInterface

    Appends a rejection handler callback to the promise, and returns a new promise resolving to the return value of the callback if it is called, or to its original fulfillment value if the promise is instead fulfilled.

  • wait($unwrap = true) : mixed

    Synchronously waits on the promise to complete.

    $unwrap controls whether or not the value of the promise is returned for a
    fulfilled promise or if an exception is thrown if the promise is rejected.
    This is set to true by default.

  • cancel()

    Attempts to cancel the promise if possible. The promise being cancelled and
    the parent most ancestor that has not yet been resolved will also be
    cancelled. Any promises waiting on the cancelled promise to resolve will also
    be cancelled.

  • getState() : string

    Returns the state of the promise. One of pending, fulfilled, or
    rejected.

  • resolve($value)

    Fulfills the promise with the given $value.

  • reject($reason)

    Rejects the promise with the given $reason.

FulfilledPromise

A fulfilled promise can be created to represent a promise that has been
fulfilled.

php
use GuzzleHttp\Promise\FulfilledPromise;

$promise = new FulfilledPromise('value');

// Fulfilled callbacks are immediately invoked.
$promise->then(function ($value) {
    echo $value;
});

RejectedPromise

A rejected promise can be created to represent a promise that has been
rejected.

php
use GuzzleHttp\Promise\RejectedPromise;

$promise = new RejectedPromise('Error');

// Rejected callbacks are immediately invoked.
$promise->then(null, function ($reason) {
    echo $reason;
});

Promise Interoperability

This library works with foreign promises that have a then method. This means
you can use Guzzle promises with React promises
for example. When a foreign promise is returned inside of a then method
callback, promise resolution will occur recursively.

php
// Create a React promise
$deferred = new React\Promise\Deferred();
$reactPromise = $deferred->promise();

// Create a Guzzle promise that is fulfilled with a React promise.
$guzzlePromise = new GuzzleHttp\Promise\Promise();
$guzzlePromise->then(function ($value) use ($reactPromise) {
    // Do something something with the value...
    // Return the React promise
    return $reactPromise;
});

Please note that wait and cancel chaining is no longer possible when forwarding
a foreign promise. You will need to wrap a third-party promise with a Guzzle
promise in order to utilize wait and cancel functions with foreign promises.

Event Loop Integration

In order to keep the stack size constant, Guzzle promises are resolved
asynchronously using a task queue. When waiting on promises synchronously, the
task queue will be automatically run to ensure that the blocking promise and
any forwarded promises are resolved. When using promises asynchronously in an
event loop, you will need to run the task queue on each tick of the loop. If
you do not run the task queue, then promises will not be resolved.

You can run the task queue using the run() method of the global task queue
instance.

php
// Get the global task queue
$queue = GuzzleHttp\Promise\Utils::queue();
$queue->run();

For example, you could use Guzzle promises with React using a periodic timer:

php
$loop = React\EventLoop\Factory::create();
$loop->addPeriodicTimer(0, [$queue, 'run']);

TODO: Perhaps adding a futureTick() on each tick would be faster?

Implementation Notes

Promise Resolution and Chaining is Handled Iteratively

By shuffling pending handlers from one owner to another, promises are
resolved iteratively, allowing for "infinite" then chaining.

php
<?php
require 'vendor/autoload.php';

use GuzzleHttp\Promise\Promise;

$parent = new Promise();
$p = $parent;

for ($i = 0; $i < 1000; $i++) {
    $p = $p->then(function ($v) {
        // The stack size remains constant (a good thing)
        echo xdebug_get_stack_depth() . ', ';
        return $v + 1;
    });
}

$parent->resolve(0);
var_dump($p->wait()); // int(1000)

When a promise is fulfilled or rejected with a non-promise value, the promise
then takes ownership of the handlers of each child promise and delivers values
down the chain without using recursion.

When a promise is resolved with another promise, the original promise transfers
all of its pending handlers to the new promise. When the new promise is
eventually resolved, all of the pending handlers are delivered the forwarded
value.

A Promise is the Deferred

Some promise libraries implement promises using a deferred object to represent
a computation and a promise object to represent the delivery of the result of
the computation. This is a nice separation of computation and delivery because
consumers of the promise cannot modify the value that will be eventually
delivered.

One side effect of being able to implement promise resolution and chaining
iteratively is that you need to be able for one promise to reach into the state
of another promise to shuffle around ownership of handlers. In order to achieve
this without making the handlers of a promise publicly mutable, a promise is
also the deferred value, allowing promises of the same parent class to reach
into and modify the private properties of promises of the same type. While this
does allow consumers of the value to modify the resolution or rejection of the
deferred, it is a small price to pay for keeping the stack size constant.

php
$promise = new Promise();
$promise->then(function ($value) { echo $value; });
// The promise is the deferred value, so you can deliver a value to it.
$promise->resolve('foo');
// prints "foo"

Upgrading from Function API

A static API was first introduced in 1.4.0, in order to mitigate problems with
functions conflicting between global and local copies of the package. The
function API will be removed in 2.0.0. A migration table has been provided here
for your convenience:

Original Function Replacement Method
queue Utils::queue
task Utils::task
promise_for Create::promiseFor
rejection_for Create::rejectionFor
exception_for Create::exceptionFor
iter_for Create::iterFor
inspect Utils::inspect
inspect_all Utils::inspectAll
unwrap Utils::unwrap
all Utils::all
some Utils::some
any Utils::any
settle Utils::settle
each Each::of
each_limit Each::ofLimit
each_limit_all Each::ofLimitAll
!is_fulfilled Is::pending
is_fulfilled Is::fulfilled
is_rejected Is::rejected
is_settled Is::settled
coroutine Coroutine::of

Security

If you discover a security vulnerability within this package, please send an email to [email protected]. All security vulnerabilities will be promptly addressed. Please do not disclose security-related issues publicly until a fix has been announced. Please see Security Policy for more information.

License

Guzzle is made available under the MIT License (MIT). Please see License File for more information.

For Enterprise

Available as part of the Tidelift Subscription

The maintainers of Guzzle and thousands of other packages are working with Tidelift to deliver commercial support and maintenance for the open source dependencies you use to build your applications. Save time, reduce risk, and improve code health, while paying the maintainers of the exact dependencies you use. Learn more.


Overview (`vendor/guzzlehttp/psr7/README.md`)

PSR-7 Message Implementation

This repository contains a full PSR-7
message implementation, several stream decorators, and some helpful
functionality like query string parsing.

Stream implementation

This package comes with a number of stream implementations and stream
decorators.

AppendStream

GuzzleHttp\Psr7\AppendStream

Reads from multiple streams, one after the other.

php
use GuzzleHttp\Psr7;

$a = Psr7\Utils::streamFor('abc, ');
$b = Psr7\Utils::streamFor('123.');
$composed = new Psr7\AppendStream([$a, $b]);

$composed->addStream(Psr7\Utils::streamFor(' Above all listen to me'));

echo $composed; // abc, 123. Above all listen to me.

BufferStream

GuzzleHttp\Psr7\BufferStream

Provides a buffer stream that can be written to fill a buffer, and read
from to remove bytes from the buffer.

This stream returns a "hwm" metadata value that tells upstream consumers
what the configured high water mark of the stream is, or the maximum
preferred size of the buffer.

php
use GuzzleHttp\Psr7;

// When more than 1024 bytes are in the buffer, it will begin returning
// false to writes. This is an indication that writers should slow down.
$buffer = new Psr7\BufferStream(1024);

CachingStream

The CachingStream is used to allow seeking over previously read bytes on
non-seekable streams. This can be useful when transferring a non-seekable
entity body fails due to needing to rewind the stream (for example, resulting
from a redirect). Data that is read from the remote stream will be buffered in
a PHP temp stream so that previously read bytes are cached first in memory,
then on disk.

php
use GuzzleHttp\Psr7;

$original = Psr7\Utils::streamFor(fopen('http://www.google.com', 'r'));
$stream = new Psr7\CachingStream($original);

$stream->read(1024);
echo $stream->tell();
// 1024

$stream->seek(0);
echo $stream->tell();
// 0

DroppingStream

GuzzleHttp\Psr7\DroppingStream

Stream decorator that begins dropping data once the size of the underlying
stream becomes too full.

php
use GuzzleHttp\Psr7;

// Create an empty stream
$stream = Psr7\Utils::streamFor();

// Start dropping data when the stream has more than 10 bytes
$dropping = new Psr7\DroppingStream($stream, 10);

$dropping->write('01234567890123456789');
echo $stream; // 0123456789

FnStream

GuzzleHttp\Psr7\FnStream

Compose stream implementations based on a hash of functions.

Allows for easy testing and extension of a provided stream without needing
to create a concrete class for a simple extension point.

php
use GuzzleHttp\Psr7;

$stream = Psr7\Utils::streamFor('hi');
$fnStream = Psr7\FnStream::decorate($stream, [
    'rewind' => function () use ($stream) {
        echo 'About to rewind - ';
        $stream->rewind();
        echo 'rewound!';
    }
]);

$fnStream->rewind();
// Outputs: About to rewind - rewound!

InflateStream

GuzzleHttp\Psr7\InflateStream

Uses PHP's zlib.inflate filter to inflate zlib (HTTP deflate, RFC1950) or gzipped (RFC1952) content.

This stream decorator converts the provided stream to a PHP stream resource,
then appends the zlib.inflate filter. The stream is then converted back
to a Guzzle stream resource to be used as a Guzzle stream.

LazyOpenStream

GuzzleHttp\Psr7\LazyOpenStream

Lazily reads or writes to a file that is opened only after an IO operation
take place on the stream.

php
use GuzzleHttp\Psr7;

$stream = new Psr7\LazyOpenStream('/path/to/file', 'r');
// The file has not yet been opened...

echo $stream->read(10);
// The file is opened and read from only when needed.

LimitStream

GuzzleHttp\Psr7\LimitStream

LimitStream can be used to read a subset or slice of an existing stream object.
This can be useful for breaking a large file into smaller pieces to be sent in
chunks (e.g. Amazon S3's multipart upload API).

php
use GuzzleHttp\Psr7;

$original = Psr7\Utils::streamFor(fopen('/tmp/test.txt', 'r+'));
echo $original->getSize();
// >>> 1048576

// Limit the size of the body to 1024 bytes and start reading from byte 2048
$stream = new Psr7\LimitStream($original, 1024, 2048);
echo $stream->getSize();
// >>> 1024
echo $stream->tell();
// >>> 0

MultipartStream

GuzzleHttp\Psr7\MultipartStream

Stream that when read returns bytes for a streaming multipart or
multipart/form-data stream.

NoSeekStream

GuzzleHttp\Psr7\NoSeekStream

NoSeekStream wraps a stream and does not allow seeking.

php
use GuzzleHttp\Psr7;

$original = Psr7\Utils::streamFor('foo');
$noSeek = new Psr7\NoSeekStream($original);

echo $noSeek->read(3);
// foo
var_export($noSeek->isSeekable());
// false
$noSeek->seek(0);
var_export($noSeek->read(3));
// NULL

PumpStream

GuzzleHttp\Psr7\PumpStream

Provides a read only stream that pumps data from a PHP callable.

When invoking the provided callable, the PumpStream will pass the amount of
data requested to read to the callable. The callable can choose to ignore
this value and return fewer or more bytes than requested. Any extra data
returned by the provided callable is buffered internally until drained using
the read() function of the PumpStream. The provided callable MUST return
false when there is no more data to read.

Implementing stream decorators

Creating a stream decorator is very easy thanks to the
GuzzleHttp\Psr7\StreamDecoratorTrait. This trait provides methods that
implement Psr\Http\Message\StreamInterface by proxying to an underlying
stream. Just use the StreamDecoratorTrait and implement your custom
methods.

For example, let's say we wanted to call a specific function each time the last
byte is read from a stream. This could be implemented by overriding the
read() method.

php
use Psr\Http\Message\StreamInterface;
use GuzzleHttp\Psr7\StreamDecoratorTrait;

class EofCallbackStream implements StreamInterface
{
    use StreamDecoratorTrait;

    private $callback;

    public function __construct(StreamInterface $stream, callable $cb)
    {
        $this->stream = $stream;
        $this->callback = $cb;
    }

    public function read($length)
    {
        $result = $this->stream->read($length);

        // Invoke the callback when EOF is hit.
        if ($this->eof()) {
            call_user_func($this->callback);
        }

        return $result;
    }
}

This decorator could be added to any existing stream and used like so:

php
use GuzzleHttp\Psr7;

$original = Psr7\Utils::streamFor('foo');

$eofStream = new EofCallbackStream($original, function () {
    echo 'EOF!';
});

$eofStream->read(2);
$eofStream->read(1);
// echoes "EOF!"
$eofStream->seek(0);
$eofStream->read(3);
// echoes "EOF!"

PHP StreamWrapper

You can use the GuzzleHttp\Psr7\StreamWrapper class if you need to use a
PSR-7 stream as a PHP stream resource.

Use the GuzzleHttp\Psr7\StreamWrapper::getResource() method to create a PHP
stream from a PSR-7 stream.

php
use GuzzleHttp\Psr7\StreamWrapper;

$stream = GuzzleHttp\Psr7\Utils::streamFor('hello!');
$resource = StreamWrapper::getResource($stream);
echo fread($resource, 6); // outputs hello!

Static API

There are various static methods available under the GuzzleHttp\Psr7 namespace.

`GuzzleHttp\Psr7\Message::toString`

public static function toString(MessageInterface $message): string

Returns the string representation of an HTTP message.

php
$request = new GuzzleHttp\Psr7\Request('GET', 'http://example.com');
echo GuzzleHttp\Psr7\Message::toString($request);

`GuzzleHttp\Psr7\Message::bodySummary`

public static function bodySummary(MessageInterface $message, int $truncateAt = 120): string|null

Get a short summary of the message body.

Will return null if the response is not printable.

`GuzzleHttp\Psr7\Message::rewindBody`

public static function rewindBody(MessageInterface $message): void

Attempts to rewind a message body and throws an exception on failure.

The body of the message will only be rewound if a call to tell()
returns a value other than 0.

`GuzzleHttp\Psr7\Message::parseMessage`

public static function parseMessage(string $message): array

Parses an HTTP message into an associative array.

The array contains the "start-line" key containing the start line of
the message, "headers" key containing an associative array of header
array values, and a "body" key containing the body of the message.

`GuzzleHttp\Psr7\Message::parseRequestUri`

public static function parseRequestUri(string $path, array $headers): string

Constructs a URI for an HTTP request message.

`GuzzleHttp\Psr7\Message::parseRequest`

public static function parseRequest(string $message): Request

Parses a request message string into a request object.

`GuzzleHttp\Psr7\Message::parseResponse`

public static function parseResponse(string $message): Response

Parses a response message string into a response object.

`GuzzleHttp\Psr7\Header::parse`

public static function parse(string|array $header): array

Parse an array of header values containing ";" separated data into an
array of associative arrays representing the header key value pair data
of the header. When a parameter does not contain a value, but just
contains a key, this function will inject a key with a '' string value.

`GuzzleHttp\Psr7\Header::normalize`

public static function normalize(string|array $header): array

Converts an array of header values that may contain comma separated
headers into an array of headers with no comma separated values.

`GuzzleHttp\Psr7\Query::parse`

public static function parse(string $str, int|bool $urlEncoding = true): array

Parse a query string into an associative array.

If multiple values are found for the same key, the value of that key
value pair will become an array. This function does not parse nested
PHP style arrays into an associative array (e.g., foo[a]=1&foo[b]=2
will be parsed into ['foo[a]' => '1', 'foo[b]' => '2']).

`GuzzleHttp\Psr7\Query::build`

public static function build(array $params, int|false $encoding = PHP_QUERY_RFC3986): string

Build a query string from an array of key value pairs.

This function can use the return value of parse() to build a query
string. This function does not modify the provided keys when an array is
encountered (like http_build_query() would).

`GuzzleHttp\Psr7\Utils::caselessRemove`

public static function caselessRemove(iterable<string> $keys, $keys, array $data): array

Remove the items given by the keys, case insensitively from the data.

`GuzzleHttp\Psr7\Utils::copyToStream`

public static function copyToStream(StreamInterface $source, StreamInterface $dest, int $maxLen = -1): void

Copy the contents of a stream into another stream until the given number
of bytes have been read.

`GuzzleHttp\Psr7\Utils::copyToString`

public static function copyToString(StreamInterface $stream, int $maxLen = -1): string

Copy the contents of a stream into a string until the given number of
bytes have been read.

`GuzzleHttp\Psr7\Utils::hash`

public static function hash(StreamInterface $stream, string $algo, bool $rawOutput = false): string

Calculate a hash of a stream.

This method reads the entire stream to calculate a rolling hash, based on
PHP's hash_init functions.

`GuzzleHttp\Psr7\Utils::modifyRequest`

public static function modifyRequest(RequestInterface $request, array $changes): RequestInterface

Clone and modify a request with the given changes.

This method is useful for reducing the number of clones needed to mutate
a message.

  • method: (string) Changes the HTTP method.
  • set_headers: (array) Sets the given headers.
  • remove_headers: (array) Remove the given headers.
  • body: (mixed) Sets the given body.
  • uri: (UriInterface) Set the URI.
  • query: (string) Set the query string value of the URI.
  • version: (string) Set the protocol version.

`GuzzleHttp\Psr7\Utils::readLine`

public static function readLine(StreamInterface $stream, int $maxLength = null): string

Read a line from the stream up to the maximum allowed buffer length.

`GuzzleHttp\Psr7\Utils::streamFor`

public static function streamFor(resource|string|null|int|float|bool|StreamInterface|callable|\Iterator $resource = '', array $options = []): StreamInterface

Create a new stream based on the input type.

Options is an associative array that can contain the following keys:

  • metadata: Array of custom metadata.
  • size: Size of the stream.

This method accepts the following $resource types:

  • Psr\Http\Message\StreamInterface: Returns the value as-is.
  • string: Creates a stream object that uses the given string as the contents.
  • resource: Creates a stream object that wraps the given PHP stream resource.
  • Iterator: If the provided value implements Iterator, then a read-only
    stream object will be created that wraps the given iterable. Each time the
    stream is read from, data from the iterator will fill a buffer and will be
    continuously called until the buffer is equal to the requested read size.
    Subsequent read calls will first read from the buffer and then call next
    on the underlying iterator until it is exhausted.
  • object with __toString(): If the object has the __toString() method,
    the object will be cast to a string and then a stream will be returned that
    uses the string value.
  • NULL: When null is passed, an empty stream object is returned.
  • callable When a callable is passed, a read-only stream object will be
    created that invokes the given callable. The callable is invoked with the
    number of suggested bytes to read. The callable can return any number of
    bytes, but MUST return false when there is no more data to return. The
    stream object that wraps the callable will invoke the callable until the
    number of requested bytes are available. Any additional bytes will be
    buffered and used in subsequent reads.
php
$stream = GuzzleHttp\Psr7\Utils::streamFor('foo');
$stream = GuzzleHttp\Psr7\Utils::streamFor(fopen('/path/to/file', 'r'));

$generator = function ($bytes) {
    for ($i = 0; $i < $bytes; $i++) {
        yield ' ';
    }
}

$stream = GuzzleHttp\Psr7\Utils::streamFor($generator(100));

`GuzzleHttp\Psr7\Utils::tryFopen`

public static function tryFopen(string $filename, string $mode): resource

Safely opens a PHP stream resource using a filename.

When fopen fails, PHP normally raises a warning. This function adds an
error handler that checks for errors and throws an exception instead.

`GuzzleHttp\Psr7\Utils::tryGetContents`

public static function tryGetContents(resource $stream): string

Safely gets the contents of a given stream.

When stream_get_contents fails, PHP normally raises a warning. This
function adds an error handler that checks for errors and throws an
exception instead.

`GuzzleHttp\Psr7\Utils::uriFor`

public static function uriFor(string|UriInterface $uri): UriInterface

Returns a UriInterface for the given value.

This function accepts a string or UriInterface and returns a
UriInterface for the given value. If the value is already a
UriInterface, it is returned as-is.

`GuzzleHttp\Psr7\MimeType::fromFilename`

public static function fromFilename(string $filename): string|null

Determines the mimetype of a file by looking at its extension.

`GuzzleHttp\Psr7\MimeType::fromExtension`

public static function fromExtension(string $extension): string|null

Maps a file extensions to a mimetype.

Upgrading from Function API

The static API was first introduced in 1.7.0, in order to mitigate problems with functions conflicting between global and local copies of the package. The function API was removed in 2.0.0. A migration table has been provided here for your convenience:

Original Function Replacement Method
str Message::toString
uri_for Utils::uriFor
stream_for Utils::streamFor
parse_header Header::parse
normalize_header Header::normalize
modify_request Utils::modifyRequest
rewind_body Message::rewindBody
try_fopen Utils::tryFopen
copy_to_string Utils::copyToString
copy_to_stream Utils::copyToStream
hash Utils::hash
readline Utils::readLine
parse_request Message::parseRequest
parse_response Message::parseResponse
parse_query Query::parse
build_query Query::build
mimetype_from_filename MimeType::fromFilename
mimetype_from_extension MimeType::fromExtension
_parse_message Message::parseMessage
_parse_request_uri Message::parseRequestUri
get_message_body_summary Message::bodySummary
_caseless_remove Utils::caselessRemove

Additional URI Methods

Aside from the standard Psr\Http\Message\UriInterface implementation in form of the GuzzleHttp\Psr7\Uri class,
this library also provides additional functionality when working with URIs as static methods.

URI Types

An instance of Psr\Http\Message\UriInterface can either be an absolute URI or a relative reference.
An absolute URI has a scheme. A relative reference is used to express a URI relative to another URI,
the base URI. Relative references can be divided into several forms according to
RFC 3986 Section 4.2:

  • network-path references, e.g. //example.com/path
  • absolute-path references, e.g. /path
  • relative-path references, e.g. subpath

The following methods can be used to identify the type of the URI.

`GuzzleHttp\Psr7\Uri::isAbsolute`

public static function isAbsolute(UriInterface $uri): bool

Whether the URI is absolute, i.e. it has a scheme.

`GuzzleHttp\Psr7\Uri::isNetworkPathReference`

public static function isNetworkPathReference(UriInterface $uri): bool

Whether the URI is a network-path reference. A relative reference that begins with two slash characters is
termed an network-path reference.

`GuzzleHttp\Psr7\Uri::isAbsolutePathReference`

public static function isAbsolutePathReference(UriInterface $uri): bool

Whether the URI is a absolute-path reference. A relative reference that begins with a single slash character is
termed an absolute-path reference.

`GuzzleHttp\Psr7\Uri::isRelativePathReference`

public static function isRelativePathReference(UriInterface $uri): bool

Whether the URI is a relative-path reference. A relative reference that does not begin with a slash character is
termed a relative-path reference.

`GuzzleHttp\Psr7\Uri::isSameDocumentReference`

public static function isSameDocumentReference(UriInterface $uri, UriInterface $base = null): bool

Whether the URI is a same-document reference. A same-document reference refers to a URI that is, aside from its
fragment component, identical to the base URI. When no base URI is given, only an empty URI reference
(apart from its fragment) is considered a same-document reference.

URI Components

Additional methods to work with URI components.

`GuzzleHttp\Psr7\Uri::isDefaultPort`

public static function isDefaultPort(UriInterface $uri): bool

Whether the URI has the default port of the current scheme. Psr\Http\Message\UriInterface::getPort may return null
or the standard port. This method can be used independently of the implementation.

`GuzzleHttp\Psr7\Uri::composeComponents`

public static function composeComponents($scheme, $authority, $path, $query, $fragment): string

Composes a URI reference string from its various components according to
RFC 3986 Section 5.3. Usually this method does not need to be called
manually but instead is used indirectly via Psr\Http\Message\UriInterface::__toString.

`GuzzleHttp\Psr7\Uri::fromParts`

public static function fromParts(array $parts): UriInterface

Creates a URI from a hash of parse_url components.

`GuzzleHttp\Psr7\Uri::withQueryValue`

public static function withQueryValue(UriInterface $uri, $key, $value): UriInterface

Creates a new URI with a specific query string value. Any existing query string values that exactly match the
provided key are removed and replaced with the given key value pair. A value of null will set the query string
key without a value, e.g. "key" instead of "key=value".

`GuzzleHttp\Psr7\Uri::withQueryValues`

public static function withQueryValues(UriInterface $uri, array $keyValueArray): UriInterface

Creates a new URI with multiple query string values. It has the same behavior as withQueryValue() but for an
associative array of key => value.

`GuzzleHttp\Psr7\Uri::withoutQueryValue`

public static function withoutQueryValue(UriInterface $uri, $key): UriInterface

Creates a new URI with a specific query string value removed. Any existing query string values that exactly match the
provided key are removed.

Cross-Origin Detection

GuzzleHttp\Psr7\UriComparator provides methods to determine if a modified URL should be considered cross-origin.

`GuzzleHttp\Psr7\UriComparator::isCrossOrigin`

public static function isCrossOrigin(UriInterface $original, UriInterface $modified): bool

Determines if a modified URL should be considered cross-origin with respect to an original URL.

Reference Resolution

GuzzleHttp\Psr7\UriResolver provides methods to resolve a URI reference in the context of a base URI according
to RFC 3986 Section 5. This is for example also what web browsers
do when resolving a link in a website based on the current request URI.

`GuzzleHttp\Psr7\UriResolver::resolve`

public static function resolve(UriInterface $base, UriInterface $rel): UriInterface

Converts the relative URI into a new URI that is resolved against the base URI.

`GuzzleHttp\Psr7\UriResolver::removeDotSegments`

public static function removeDotSegments(string $path): string

Removes dot segments from a path and returns the new path according to
RFC 3986 Section 5.2.4.

`GuzzleHttp\Psr7\UriResolver::relativize`

public static function relativize(UriInterface $base, UriInterface $target): UriInterface

Returns the target URI as a relative reference from the base URI. This method is the counterpart to resolve():

php
(string) $target === (string) UriResolver::resolve($base, UriResolver::relativize($base, $target))

One use-case is to use the current request URI as base URI and then generate relative links in your documents
to reduce the document size or offer self-contained downloadable document archives.

php
$base = new Uri('http://example.com/a/b/');
echo UriResolver::relativize($base, new Uri('http://example.com/a/b/c'));  // prints 'c'.
echo UriResolver::relativize($base, new Uri('http://example.com/a/x/y'));  // prints '../x/y'.
echo UriResolver::relativize($base, new Uri('http://example.com/a/b/?q')); // prints '?q'.
echo UriResolver::relativize($base, new Uri('http://example.org/a/b/'));   // prints '//example.org/a/b/'.

Normalization and Comparison

GuzzleHttp\Psr7\UriNormalizer provides methods to normalize and compare URIs according to
RFC 3986 Section 6.

`GuzzleHttp\Psr7\UriNormalizer::normalize`

public static function normalize(UriInterface $uri, $flags = self::PRESERVING_NORMALIZATIONS): UriInterface

Returns a normalized URI. The scheme and host component are already normalized to lowercase per PSR-7 UriInterface.
This methods adds additional normalizations that can be configured with the $flags parameter which is a bitmask
of normalizations to apply. The following normalizations are available:

  • UriNormalizer::PRESERVING_NORMALIZATIONS

    Default normalizations which only include the ones that preserve semantics.

  • UriNormalizer::CAPITALIZE_PERCENT_ENCODING

    All letters within a percent-encoding triplet (e.g., "%3A") are case-insensitive, and should be capitalized.

    Example: http://example.org/a%c2%b1b → http://example.org/a%C2%B1b

  • UriNormalizer::DECODE_UNRESERVED_CHARACTERS

    Decodes percent-encoded octets of unreserved characters. For consistency, percent-encoded octets in the ranges of
    ALPHA (%41–%5A and %61–%7A), DIGIT (%30–%39), hyphen (%2D), period (%2E), underscore (%5F), or tilde (%7E) should
    not be created by URI producers and, when found in a URI, should be decoded to their corresponding unreserved
    characters by URI normalizers.

    Example: http://example.org/%7Eusern%61me/ → http://example.org/~username/

  • UriNormalizer::CONVERT_EMPTY_PATH

    Converts the empty path to "/" for http and https URIs.

    Example: http://example.org → http://example.org/

  • UriNormalizer::REMOVE_DEFAULT_HOST

    Removes the default host of the given URI scheme from the URI. Only the "file" scheme defines the default host
    "localhost". All of file:/myfile, file:///myfile, and file://localhost/myfile are equivalent according to
    RFC 3986.

    Example: file://localhost/myfile → file:///myfile

  • UriNormalizer::REMOVE_DEFAULT_PORT

    Removes the default port of the given URI scheme from the URI.

    Example: http://example.org:80/ → http://example.org/

  • UriNormalizer::REMOVE_DOT_SEGMENTS

    Removes unnecessary dot-segments. Dot-segments in relative-path references are not removed as it would
    change the semantics of the URI reference.

    Example: http://example.org/../a/b/../c/./d.html → http://example.org/a/c/d.html

  • UriNormalizer::REMOVE_DUPLICATE_SLASHES

    Paths which include two or more adjacent slashes are converted to one. Webservers usually ignore duplicate slashes
    and treat those URIs equivalent. But in theory those URIs do not need to be equivalent. So this normalization
    may change the semantics. Encoded slashes (%2F) are not removed.

    Example: http://example.org//foo///bar.html → http://example.org/foo/bar.html

  • UriNormalizer::SORT_QUERY_PARAMETERS

    Sort query parameters with their values in alphabetical order. However, the order of parameters in a URI may be
    significant (this is not defined by the standard). So this normalization is not safe and may change the semantics
    of the URI.

    Example: ?lang=en&article=fred → ?article=fred&lang=en

`GuzzleHttp\Psr7\UriNormalizer::isEquivalent`

public static function isEquivalent(UriInterface $uri1, UriInterface $uri2, $normalizations = self::PRESERVING_NORMALIZATIONS): bool

Whether two URIs can be considered equivalent. Both URIs are normalized automatically before comparison with the given
$normalizations bitmask. The method also accepts relative URI references and returns true when they are equivalent.
This of course assumes they will be resolved against the same base URI. If this is not the case, determination of
equivalence or difference of relative references does not mean anything.

Version Guidance

Version Status PHP Version
1.x Security fixes >=5.4,<8.1
2.x Latest ^7.2.5 || ^8.0

Security

If you discover a security vulnerability within this package, please send an email to [email protected]. All security vulnerabilities will be promptly addressed. Please do not disclose security-related issues publicly until a fix has been announced. Please see Security Policy for more information.

License

Guzzle is made available under the MIT License (MIT). Please see License File for more information.

For Enterprise

Available as part of the Tidelift Subscription

The maintainers of Guzzle and thousands of other packages are working with Tidelift to deliver commercial support and maintenance for the open source dependencies you use to build your applications. Save time, reduce risk, and improve code health, while paying the maintainers of the exact dependencies you use. Learn more.


Overview (`vendor/illuminate/database/README.md`)

Illuminate Database

The Illuminate Database component is a full database toolkit for PHP, providing an expressive query builder, ActiveRecord style ORM, and schema builder. It currently supports MySQL, Postgres, SQL Server, and SQLite. It also serves as the database layer of the Laravel PHP framework.

Usage Instructions

First, create a new "Capsule" manager instance. Capsule aims to make configuring the library for usage outside of the Laravel framework as easy as possible.

php
use Illuminate\Database\Capsule\Manager as Capsule;

$capsule = new Capsule;

$capsule->addConnection([
    'driver'    => 'mysql',
    'host'      => 'localhost',
    'database'  => 'database',
    'username'  => 'root',
    'password'  => 'password',
    'charset'   => 'utf8',
    'collation' => 'utf8_unicode_ci',
    'prefix'    => '',
]);

// Set the event dispatcher used by Eloquent models... (optional)
use Illuminate\Events\Dispatcher;
use Illuminate\Container\Container;
$capsule->setEventDispatcher(new Dispatcher(new Container));

// Make this Capsule instance available globally via static methods... (optional)
$capsule->setAsGlobal();

// Setup the Eloquent ORM... (optional; unless you've used setEventDispatcher())
$capsule->bootEloquent();

composer require "illuminate/events" required when you need to use observers with Eloquent.

Once the Capsule instance has been registered. You may use it like so:

Using The Query Builder

php
$users = Capsule::table('users')->where('votes', '>', 100)->get();

Other core methods may be accessed directly from the Capsule in the same manner as from the DB facade:

php
$results = Capsule::select('select * from users where id = ?', [1]);

Using The Schema Builder

php
Capsule::schema()->create('users', function ($table) {
    $table->increments('id');
    $table->string('email')->unique();
    $table->timestamps();
});

Using The Eloquent ORM

php
class User extends Illuminate\Database\Eloquent\Model {}

$users = User::where('votes', '>', 1)->get();

For further documentation on using the various database facilities this library provides, consult the Laravel framework documentation.


Overview (`vendor/khanamiryan/qrcode-detector-decoder/README.md`)

QR code decoder / reader for PHP

This is a PHP library to detect and decode QR-codes.This is first and only QR code reader that works without extensions.
Ported from ZXing library

Installation

The recommended method of installing this library is via Composer.

Run the following command from your project root:

bash
$ composer require khanamiryan/qrcode-detector-decoder

Usage

php
require __DIR__ . "/vendor/autoload.php";
$qrcode = new QrReader('path/to_image');
$text = $qrcode->text(); //return decoded text from QR Code

Requirements

  • PHP >= 5.6
  • GD Library

Contributing

You can help the project by adding features, cleaning the code, adding composer and other.

  1. Fork it
  2. Create your feature branch: git checkout -b my-new-feature
  3. Commit your changes: git commit -am 'Add some feature'
  4. Push to the branch: git push origin my-new-feature
  5. Submit a pull request

Overview (`vendor/mrgoon/aliyun-sms-sdk/README.md`)

阿里云短信服务核心代码

  • 网上一些开源项目的更新时间用的相对较老的版本,使用的request文件是2016-09-27
  • 本项目更新于2017-05-25

Overview (`vendor/mrgoon/aliyun-sms/README.md`)

介绍

阿里大于关闭了新用户渠道,迁移到阿里云短信服务上,然而阿里云短信服务在5月底更新了api。
在github上找了一下,轮子都是基于2016年的接口,非常难受。
自己造了一个轮子,亲测可用。

  • 安装
    composer require mrgoon/aliyun-sms

基于laravel框架的使用方法

  • 加载
    在config/app的providers中添加
    Mrgoon\AliSms\ServiceProvider::class

同时,可以选择性添加aliases

控制台运行:
php artisan vendor:publish

根据新增的aliyunsms.php 文件,在.env文件中添加环境变量:

text
ALIYUN_SMS_AK=your access key
ALIYUN_SMS_AS=your secret key
ALIYUN_SMS_SIGN_NAME=sign name
  • 使用
text
$aliSms = new AliSms();
$response = $aliSms->sendSms('phone number', 'SMS_code', ['name'=> 'value in your template']);
//dump($response);

非laravel框架的使用方法

  • 加载方式通过composer,不变
  • 使用样例代码如下:
text
$config = [
        'access_key' => 'your access key',
        'access_secret' => 'your access secret',
        'sign_name' => 'your sign name',
    ];

    $aliSms = new Mrgoon\AliSms\AliSms();
    $response = $sms->sendSms('phone number', 'tempplate code', ['name'=> 'value in your template'], $config);

Overview (`vendor/nesbot/carbon/readme.md`)

Carbon





An international PHP extension for DateTime. https://carbon.nesbot.com

text
/* Detailed source-code truncated for AI context efficiency. */

Get supported nesbot/carbon with the Tidelift Subscription

Installation

With Composer

text
$ composer require nesbot/carbon
json
{
    "require": {
        "nesbot/carbon": "^2.16"
    }
}
php
<?php
require 'vendor/autoload.php';

use Carbon\Carbon;

printf("Now: %s", Carbon::now());

Without Composer

Why are you not using composer? Download the Carbon latest release and put the contents of the ZIP archive into a directory in your project. Then require the file autoload.php to get all classes and dependencies loaded on need.

php
<?php
require 'path-to-Carbon-directory/autoload.php';

use Carbon\Carbon;

printf("Now: %s", Carbon::now());

Docs

https://carbon.nesbot.com/docs

Security contact information

To report a security vulnerability, please use the
Tidelift security contact.
Tidelift will coordinate the fix and disclosure.

Credits

Contributors

This project exists thanks to all the people who contribute.

Translators

Thanks to people helping us to translate Carbon in so many languages

Sponsors

Support this project by becoming a sponsor. Your logo will show up here with a link to your website.











[Become a sponsor]

Backers

Thank you to all our backers! 🙏

[Become a backer]

Carbon for enterprise

Available as part of the Tidelift Subscription.

The maintainers of Carbon and thousands of other packages are working with Tidelift to deliver commercial support and maintenance for the open source dependencies you use to build your applications. Save time, reduce risk, and improve code health, while paying the maintainers of the exact dependencies you use. Learn more.


Overview (`vendor/phpmailer/phpmailer/README.md`)







Features

  • Probably the world's most popular code for sending email from PHP!
  • Used by many open-source projects: WordPress, Drupal, 1CRM, SugarCRM, Yii, Joomla! and many more
  • Integrated SMTP support – send without a local mail server
  • Send emails with multiple To, CC, BCC and Reply-to addresses
  • Multipart/alternative emails for mail clients that do not read HTML email
  • Add attachments, including inline
  • Support for UTF-8 content and 8bit, base64, binary, and quoted-printable encodings
  • SMTP authentication with LOGIN, PLAIN, CRAM-MD5, and XOAUTH2 mechanisms over SMTPS and SMTP+STARTTLS transports
  • Validates email addresses automatically
  • Protects against header injection attacks
  • Error messages in over 50 languages!
  • DKIM and S/MIME signing support
  • Compatible with PHP 5.5 and later, including PHP 8.1
  • Namespaced to prevent name clashes
  • Much more!

Why you might need it

Many PHP developers need to send email from their code. The only PHP function that supports this directly is mail(). However, it does not provide any assistance for making use of popular features such as encryption, authentication, HTML messages, and attachments.

Formatting email correctly is surprisingly difficult. There are myriad overlapping (and conflicting) standards, requiring tight adherence to horribly complicated formatting and encoding rules – the vast majority of code that you'll find online that uses the mail() function directly is just plain wrong, if not unsafe!

The PHP mail() function usually sends via a local mail server, typically fronted by a sendmail binary on Linux, BSD, and macOS platforms, however, Windows usually doesn't include a local mail server; PHPMailer's integrated SMTP client allows email sending on all platforms without needing a local mail server. Be aware though, that the mail() function should be avoided when possible; it's both faster and safer to use SMTP to localhost.

Please don't be tempted to do it yourself – if you don't use PHPMailer, there are many other excellent libraries that
you should look at before rolling your own. Try SwiftMailer
, Laminas/Mail, ZetaComponents etc.

License

This software is distributed under the LGPL 2.1 license, along with the GPL Cooperation Commitment. Please read LICENSE for information on the software availability and distribution.

Installation & loading

PHPMailer is available on Packagist (using semantic versioning), and installation via Composer is the recommended way to install PHPMailer. Just add this line to your composer.json file:

json
"phpmailer/phpmailer": "^6.5"

or run

sh
composer require phpmailer/phpmailer

Note that the vendor folder and the vendor/autoload.php script are generated by Composer; they are not part of PHPMailer.

If you want to use the Gmail XOAUTH2 authentication class, you will also need to add a dependency on the league/oauth2-client package in your composer.json.

Alternatively, if you're not using Composer, you
can download PHPMailer as a zip file, (note that docs and examples are not included in the zip file), then copy the contents of the PHPMailer folder into one of the include_path directories specified in your PHP configuration and load each class file manually:

php
<?php
use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\Exception;

require 'path/to/PHPMailer/src/Exception.php';
require 'path/to/PHPMailer/src/PHPMailer.php';
require 'path/to/PHPMailer/src/SMTP.php';

If you're not using the SMTP class explicitly (you're probably not), you don't need a use line for the SMTP class. Even if you're not using exceptions, you do still need to load the Exception class as it is used internally.

Legacy versions

PHPMailer 5.2 (which is compatible with PHP 5.0 — 7.0) is no longer supported, even for security updates. You will find the latest version of 5.2 in the 5.2-stable branch. If you're using PHP 5.5 or later (which you should be), switch to the 6.x releases.

Upgrading from 5.2

The biggest changes are that source files are now in the src/ folder, and PHPMailer now declares the namespace PHPMailer\PHPMailer. This has several important effects – read the upgrade guide for more details.

Minimal installation

While installing the entire package manually or with Composer is simple, convenient, and reliable, you may want to include only vital files in your project. At the very least you will need src/PHPMailer.php. If you're using SMTP, you'll need src/SMTP.php, and if you're using POP-before SMTP (very unlikely!), you'll need src/POP3.php. You can skip the language folder if you're not showing errors to users and can make do with English-only errors. If you're using XOAUTH2 you will need src/OAuth.php as well as the Composer dependencies for the services you wish to authenticate with. Really, it's much easier to use Composer!

A Simple Example

text
/* Detailed source-code truncated for AI context efficiency. */

You'll find plenty to play with in the examples folder, which covers many common scenarios including sending through gmail, building contact forms, sending to mailing lists, and more.

If you are re-using the instance (e.g. when sending to a mailing list), you may need to clear the recipient list to avoid sending duplicate messages. See the mailing list example for further guidance.

That's it. You should now be ready to use PHPMailer!

Localization

PHPMailer defaults to English, but in the language folder you'll find many translations for PHPMailer error messages that you may encounter. Their filenames contain ISO 639-1 language code for the translations, for example fr for French. To specify a language, you need to tell PHPMailer which one to use, like this:

php
//To load the French version
$mail->setLanguage('fr', '/optional/path/to/language/directory/');

We welcome corrections and new languages – if you're looking for corrections, run the PHPMailerLangTest.php script in the tests folder and it will show any missing translations.

Documentation

Start reading at the GitHub wiki. If you're having trouble, head for the troubleshooting guide as it's frequently updated.

Examples of how to use PHPMailer for common scenarios can be found in the examples folder. If you're looking for a good starting point, we recommend you start with the Gmail example.

To reduce PHPMailer's deployed code footprint, examples are not included if you load PHPMailer via Composer or via GitHub's zip file download, so you'll need to either clone the git repository or use the above links to get to the examples directly.

Complete generated API documentation is available online.

You can generate complete API-level documentation by running phpdoc in the top-level folder, and documentation will appear in the docs folder, though you'll need to have PHPDocumentor installed. You may find the unit tests a good reference for how to do various operations such as encryption.

If the documentation doesn't cover what you need, search the many questions on Stack Overflow, and before you ask a question about "SMTP Error: Could not connect to SMTP host.", read the troubleshooting guide.

Tests

PHPMailer tests use PHPUnit 9, with a polyfill to let 9-style tests run on older PHPUnit and PHP versions.

If this isn't passing, is there something you can do to help?

Security

Please disclose any vulnerabilities found responsibly – report security issues to the maintainers privately.

See SECURITY and PHPMailer's security advisories on GitHub.

Contributing

Please submit bug reports, suggestions and pull requests to the GitHub issue tracker.

We're particularly interested in fixing edge-cases, expanding test coverage and updating translations.

If you found a mistake in the docs, or want to add something, go ahead and amend the wiki – anyone can edit it.

If you have git clones from prior to the move to the PHPMailer GitHub organisation, you'll need to update any remote URLs referencing the old GitHub location with a command like this from within your clone:

sh
git remote set-url upstream https://github.com/PHPMailer/PHPMailer.git

Please don't use the SourceForge or Google Code projects any more; they are obsolete and no longer maintained.

Sponsorship

Development time and resources for PHPMailer are provided by Smartmessages.net, the world's only privacy-first email marketing system.

Donations are very welcome, whether in beer 🍺, T-shirts 👕, or cold, hard cash 💰. Sponsorship through GitHub is a simple and convenient way to say "thank you" to PHPMailer's maintainers and contributors – just click the "Sponsor" button on the project page. If your company uses PHPMailer, consider taking part in Tidelift's enterprise support programme.

PHPMailer For Enterprise

Available as part of the Tidelift Subscription.

The maintainers of PHPMailer and thousands of other packages are working with Tidelift to deliver commercial
support and maintenance for the open source packages you use to build your applications. Save time, reduce risk, and
improve code health, while paying the maintainers of the exact packages you
use. Learn more.

Changelog

See changelog.

History

  • PHPMailer was originally written in 2001 by Brent R. Matzelle as a SourceForge project.
  • Marcus Bointon (coolbru on SF) and Andy Prevost (codeworxtech) took over the project in 2004.
  • Became an Apache incubator project on Google Code in 2010, managed by Jim Jagielski.
  • Marcus created his fork on GitHub in 2008.
  • Jim and Marcus decide to join forces and use GitHub as the canonical and official repo for PHPMailer in 2013.
  • PHPMailer moves to the PHPMailer organisation on GitHub in 2013.

What's changed since moving from SourceForge?

  • Official successor to the SourceForge and Google Code projects.
  • Test suite.
  • Continuous integration with Github Actions.
  • Composer support.
  • Public development.
  • Additional languages and language strings.
  • CRAM-MD5 authentication support.
  • Preserves full repo history of authors, commits and branches from the original SourceForge project.

Overview (`vendor/psr/container/README.md`)

Container interface

This repository holds all interfaces related to PSR-11 (Container Interface).

Note that this is not a Container implementation of its own. It is merely abstractions that describe the components of a Dependency Injection Container.

The installable package and implementations are listed on Packagist.


Overview (`vendor/psr/http-client/README.md`)

HTTP Client

This repository holds all the common code related to PSR-18 (HTTP Client).

Note that this is not a HTTP Client implementation of its own. It is merely abstractions that describe the components of a HTTP Client.

The installable package and implementations are listed on Packagist.


Overview (`vendor/psr/http-factory/README.md`)

HTTP Factories

This repository holds all interfaces related to PSR-17 (HTTP Message Factories).
Please refer to the specification for a description.

You can find implementations of the specification by looking for packages providing the
psr/http-factory-implementation virtual package.


Overview (`vendor/psr/http-message/README.md`)

PSR Http Message

This repository holds all interfaces/classes/traits related to
PSR-7.

Note that this is not a HTTP message implementation of its own. It is merely an
interface that describes a HTTP message. See the specification for more details.

Usage

We'll certainly need some stuff in here.


Overview (`vendor/psr/simple-cache/README.md`)

PHP FIG Simple Cache PSR

This repository holds all interfaces related to PSR-16.

Note that this is not a cache implementation of its own. It is merely an interface that describes a cache implementation. See the specification for more details.

You can find implementations of the specification by looking for packages providing the psr/simple-cache-implementation virtual package.


Overview (`vendor/rah/danpu/README.md`)

Danpu - MySQL dump tool for PHP

Packagist | Downloads | Issues | Donate

Danpu is a dependency-free, cross-platform, portable PHP library for backing up MySQL databases. It has no hard dependencies, and is fit for restricted environments where security is key and access is limited. Danpu requires nothing more than access to your database, PDO and a directory it can write the backup to. The script is optimized and has low memory-footprint, allowing it to handle even larger databases.

Danpu supports backing up table structures, the data itself, views and triggers. Created dump files can optionally be compressed to save space, and generated SQL output is optimized for compatibility.

Requirements

Minimum:

  • PHP 5.3.0 or newer
  • MySQL 4.1.0 or newer
  • PDO

Recommended, but optional:

  • PHP 5.4.0 or newer
  • MySQL 5.0.11 or newer
  • zlib

Backing up views and triggers requires MySQL 5.0.11 or newer.

Install

Using Composer:

text
$ composer require rah/danpu

Usage

To create a new backup or import one, configure a new Dump instance and pass it to one of the worker classes. To begin, first make sure you have included Composer's autoloader file in your project:

php
require './vendor/autoload.php';

If you are already using other Composer packages, or a modern Composer-managed framework, this should be taken care of already. If not, merely add the autoloader to your base bootstrap includes. See Composer's documentation for more information.

Take a backup

Backups can be created with the Export class. The class exports the database to a SQL file, or throws exceptions on errors. The file is compressed if the target filename ends to a .gz extension.

php
use Rah\Danpu\Dump;
use Rah\Danpu\Export;

try {
    $dump = new Dump;
    $dump
        ->file('/path/to/target/dump/file.sql')
        ->dsn('mysql:dbname=database;host=localhost')
        ->user('username')
        ->pass('password')
        ->tmp('/tmp');

    new Export($dump);
} catch (\Exception $e) {
    echo 'Export failed with message: ' . $e->getMessage();
}

The database is dumped in chunks, one row at the time without buffering huge amount of data to the memory. This makes the script very memory efficient, and can allow Danpu to handle databases of any size, given the system limitations of course. You physically won't be able backup rows that take more memory than can be allocated to PHP, nor write backups if there isn't enough space for the files.

Import a backup

Danpu can also import its own backups using the Import class. While the importer works with backups it has made, it doesn't accept freely formatted SQL. The importer is pretty strict about formatting, and expects exactly the same format as generated by Danpu. It expects that values in statements are escaped properly, including newlines, queries have to end to a semicolon and statements preferably should not wrap to multiple lines.

To import a backup, create a new instance of the Import class. It uncompresses any .gz files before importing.

php
use Rah\Danpu\Dump;
use Rah\Danpu\Import;

try {
    $dump = new Dump;
    $dump
        ->file('/path/to/imported/file.sql')
        ->dsn('mysql:dbname=database;host=localhost')
        ->user('username')
        ->pass('password')
        ->tmp('/tmp');

    new Import($dump);
} catch (\Exception $e) {
    echo 'Import failed with message: ' . $e->getMessage();
}

Options

In addition to the mandatory connection and file location, Danpu accepts various optional configuration options. These include filtering tables and views by prefix, ignoring tables and creating dumps without row data. See the src/Rah/Danpu/Config.php for full list of options. The source file contains detailed documentation blocks, outlining each option.

Troubleshooting

Running out of memory, backup taking too long

As with any PHP script, Danpu is restricted by the safe limits you have set for PHP. When dealing with larger databases, taking a backup will take longer and require more memory. If you find yourself hitting the maximum execution time or running out of memory, its time to increase the limits enough to let the script to work.

PHP lets you to change these limits with its configuration options, which can be modified temporarily during script execution, or in global configuration files. The configuration options you will be the most interested in, are memory_limit and max_execution_time, and possibly ignore_user_abort. You can change these values in your script before running a backup with Danpu:

php
ini_set('memory_limit', '256M');
set_time_limit(0);
ignore_user_abort(true);

This of course requires that you have access to these values and you actually have more memory to give. Keep in mind that PHP may be affected by other limitations, such as your web server.


Overview (`vendor/ralouphie/getallheaders/README.md`)

getallheaders

PHP getallheaders() polyfill. Compatible with PHP >= 5.3.





This is a simple polyfill for getallheaders().

Install

For PHP version >= 5.6:

text
composer require ralouphie/getallheaders

For PHP version < 5.6:

text
composer require ralouphie/getallheaders "^2"

Overview (`vendor/smarty/smarty/README.md`)

Smarty 3 template engine

smarty.net

Documentation

For documentation see
www.smarty.net/docs/en/

Requirements

Smarty can be run with PHP 5.2 to PHP 7.4.

Distribution repository

Smarty 3.1.28 introduces run time template inheritance

Read the NEW_FEATURES and INHERITANCE_RELEASE_NOTES file for recent extensions to Smarty 3.1 functionality

Smarty versions 3.1.11 or later are now on GitHub and can be installed with Composer.

The "smarty/smarty" package will start at libs/.... subfolder.

To get the latest stable version of Smarty 3.1 use:

json
"require": {
    "smarty/smarty": "~3.1"
}

in your composer.json file.

To get the trunk version use:

json
"require": {
    "smarty/smarty": "~3.1@dev"
}

For a specific version use something like:

json
"require": {
    "smarty/smarty": "3.1.19"
}

PHPUnit test can be installed by corresponding composer entries like:

json
"require": {
    "smarty/smarty-phpunit": "3.1.19"
}

Similar applies for the lexer/parser generator.

json
"require": {
    "smarty/smarty-lexer": "3.1.19"
}

Or you could use:

json
"require": {
    "smarty/smarty-dev": "3.1.19"
}

Which is a wrapper to install all 3 packages.

Composer can also be used for Smarty2 versions 2.6.24 to 2.6.30.


Overview (`vendor/symfony/console/README.md`)

Console Component

The Console component eases the creation of beautiful and testable command line
interfaces.

The Console component for Symfony 5.4/6.0 is backed by Les-Tilleuls.coop.

Les-Tilleuls.coop is a team of 50+ Symfony experts who can help you design, develop and
fix your projects. We provide a wide range of professional services including development,
consulting, coaching, training and audits. We also are highly skilled in JS, Go and DevOps.
We are a worker cooperative!

Help Symfony by sponsoring its development!

Resources

Credits

Resources/bin/hiddeninput.exe is a third party binary provided within this
component. Find sources and license at https://github.com/Seldaek/hidden-input.


Overview (`vendor/symfony/deprecation-contracts/README.md`)

Symfony Deprecation Contracts

A generic function and convention to trigger deprecation notices.

This package provides a single global function named trigger_deprecation() that triggers silenced deprecation notices.

By using a custom PHP error handler such as the one provided by the Symfony ErrorHandler component,
the triggered deprecations can be caught and logged for later discovery, both on dev and prod environments.

The function requires at least 3 arguments:

  • the name of the Composer package that is triggering the deprecation
  • the version of the package that introduced the deprecation
  • the message of the deprecation
  • more arguments can be provided: they will be inserted in the message using printf() formatting

Example:

php
trigger_deprecation('symfony/blockchain', '8.9', 'Using "%s" is deprecated, use "%s" instead.', 'bitcoin', 'fabcoin');

This will generate the following message:
Since symfony/blockchain 8.9: Using "bitcoin" is deprecated, use "fabcoin" instead.

While not necessarily recommended, the deprecation notices can be completely ignored by declaring an empty
function trigger_deprecation() {} in your application.


Overview (`vendor/symfony/polyfill-ctype/README.md`)

Symfony Polyfill / Ctype

This component provides ctype_* functions to users who run php versions without the ctype extension.

More information can be found in the
main Polyfill README.

License

This library is released under the MIT license.


Overview (`vendor/symfony/polyfill-intl-grapheme/README.md`)

Symfony Polyfill / Intl: Grapheme

This component provides a partial, native PHP implementation of the
Grapheme functions from the
Intl extension.

  • grapheme_extract: Extract a sequence of grapheme
    clusters from a text buffer, which must be encoded in UTF-8
  • grapheme_stripos: Find position (in grapheme units)
    of first occurrence of a case-insensitive string
  • grapheme_stristr: Returns part of haystack string
    from the first occurrence of case-insensitive needle to the end of haystack
  • grapheme_strlen: Get string length in grapheme units
  • grapheme_strpos: Find position (in grapheme units)
    of first occurrence of a string
  • grapheme_strripos: Find position (in grapheme units)
    of last occurrence of a case-insensitive string
  • grapheme_strrpos: Find position (in grapheme units)
    of last occurrence of a string
  • grapheme_strstr: Returns part of haystack string from
    the first occurrence of needle to the end of haystack
  • grapheme_substr: Return part of a string

More information can be found in the
main Polyfill README.

License

This library is released under the MIT license.


Overview (`vendor/symfony/polyfill-intl-normalizer/README.md`)

Symfony Polyfill / Intl: Normalizer

This component provides a fallback implementation for the
Normalizer class provided
by the Intl extension.

More information can be found in the
main Polyfill README.

License

This library is released under the MIT license.


Overview (`vendor/symfony/polyfill-mbstring/README.md`)

Symfony Polyfill / Mbstring

This component provides a partial, native PHP implementation for the
Mbstring extension.

More information can be found in the
main Polyfill README.

License

This library is released under the MIT license.


Overview (`vendor/symfony/polyfill-php73/README.md`)

Symfony Polyfill / Php73

This component provides functions added to PHP 7.3 core:

More information can be found in the
main Polyfill README.

License

This library is released under the MIT license.


Overview (`vendor/symfony/polyfill-php80/README.md`)

Symfony Polyfill / Php80

This component provides features added to PHP 8.0 core:

More information can be found in the
main Polyfill README.

License

This library is released under the MIT license.


Overview (`vendor/symfony/service-contracts/README.md`)

Symfony Service Contracts

A set of abstractions extracted out of the Symfony components.

Can be used to build on semantics that the Symfony components proved useful - and
that already have battle tested implementations.

See https://github.com/symfony/contracts/blob/main/README.md for more information.


Overview (`vendor/symfony/string/README.md`)

String Component

The String component provides an object-oriented API to strings and deals
with bytes, UTF-8 code points and grapheme clusters in a unified way.

Resources


Overview (`vendor/symfony/translation-contracts/README.md`)

Symfony Translation Contracts

A set of abstractions extracted out of the Symfony components.

Can be used to build on semantics that the Symfony components proved useful - and
that already have battle tested implementations.

See https://github.com/symfony/contracts/blob/main/README.md for more information.


Overview (`vendor/symfony/translation/README.md`)

Translation Component

The Translation component provides tools to internationalize your application.

Getting Started

text
$ composer require symfony/translation
php
use Symfony\Component\Translation\Translator;
use Symfony\Component\Translation\Loader\ArrayLoader;

$translator = new Translator('fr_FR');
$translator->addLoader('array', new ArrayLoader());
$translator->addResource('array', [
    'Hello World!' => 'Bonjour !',
], 'fr_FR');

echo $translator->trans('Hello World!'); // outputs « Bonjour ! »

The Translation component for Symfony 5.4/6.0 is backed by:

  • Crowdin, a cloud-based localization management software helping teams to go global and stay agile.
  • Lokalise, a continuous localization and translation management platform that integrates into your development workflow so you can ship localized products, faster.

Help Symfony by sponsoring its development!

Resources


Overview (`vendor/symfony/var-dumper/README.md`)

VarDumper Component

The VarDumper component provides mechanisms for walking through any arbitrary
PHP variable. It provides a better dump() function that you can use instead
of var_dump().

Resources


Overview (`vendor/voku/portable-ascii/README.md`)









🔡 Portable ASCII

Description

It is written in PHP (PHP 7+) and can work without "mbstring", "iconv" or any other extra encoding php-extension on your server.

The benefit of Portable ASCII is that it is easy to use, easy to bundle.

The project based on ...

Index

Alternative

If you like a more Object Oriented Way to edit strings, then you can take a look at voku/Stringy, it's a fork of "danielstjules/Stringy" but it used the "Portable ASCII"-Class and some extra methods.

php
// Portable ASCII
use voku\helper\ASCII;
ASCII::to_transliterate('déjà σσς iıii'); // 'deja sss iiii'

// voku/Stringy
use Stringy\Stringy as S;
$stringy = S::create('déjà σσς iıii');
$stringy->toTransliterate();              // 'deja sss iiii'

Install "Portable ASCII" via "composer require"

shell
composer require voku/portable-ascii

Why Portable ASCII?[]()

I need ASCII char handling in different classes and before I added this functions into "Portable UTF-8",
but this repo is more modular and portable, because it has no dependencies.

Requirements and Recommendations

  • No extensions are required to run this library. Portable ASCII only needs PCRE library that is available by default since PHP 4.2.0 and cannot be disabled since PHP 5.3.0. "\u" modifier support in PCRE for ASCII handling is not a must.
  • PHP 7.0 is the minimum requirement
  • PHP 8.0 is also supported

Usage

Example: ASCII::to_ascii()

php
echo ASCII::to_ascii('�Düsseldorf�', 'de');
  
  // will output
  // Duesseldorf

  echo ASCII::to_ascii('�Düsseldorf�', 'en');
  
  // will output
  // Dusseldorf

Portable ASCII | API

The API from the "ASCII"-Class is written as small static methods.

Class methods

charsArray charsArrayWithMultiLanguageValues charsArrayWithOneLanguage charsArrayWithSingleLanguageValues
clean getAllLanguages is_ascii normalize_msword
normalize_whitespace remove_invisible_characters to_ascii to_filename
to_slugify to_transliterate

charsArray(bool $replace_extra_symbols): array

↑
Returns an replacement array for ASCII methods.

EXAMPLE:
$array = ASCII::charsArray();
var_dump($array['ru']['б']); // 'b'

Parameters:

  • bool $replace_extra_symbols [optional] Add some more replacements e.g. "£" with " pound ".

Return:

  • array

charsArrayWithMultiLanguageValues(bool $replace_extra_symbols): array

↑
Returns an replacement array for ASCII methods with a mix of multiple languages.

EXAMPLE:
$array = ASCII::charsArrayWithMultiLanguageValues();
var_dump($array['b']); // ['β', 'б', 'ဗ', 'ბ', 'ب']

Parameters:

  • bool $replace_extra_symbols [optional] Add some more replacements e.g. "£" with " pound ".

Return:

  • array An array of replacements.

charsArrayWithOneLanguage(string $language, bool $replace_extra_symbols, bool $asOrigReplaceArray): array

↑
Returns an replacement array for ASCII methods with one language.

For example, German will map 'ä' to 'ae', while other languages
will simply return e.g. 'a'.

EXAMPLE:
$array = ASCII::charsArrayWithOneLanguage('ru');
$tmpKey = \array_search('yo', $array['replace']);
echo $array['orig'][$tmpKey]; // 'ё'

Parameters:

  • string $language [optional] Language of the source string e.g.: en, de_at, or de-ch. (default is 'en') | ASCII::*_LANGUAGE_CODE
  • bool $replace_extra_symbols [optional] Add some more replacements e.g. "£" with " pound ".
  • bool $asOrigReplaceArray [optional] TRUE === return {orig: string[], replace: string[]} array

Return:

  • array An array of replacements.

charsArrayWithSingleLanguageValues(bool $replace_extra_symbols, bool $asOrigReplaceArray): array

↑
Returns an replacement array for ASCII methods with multiple languages.

EXAMPLE:
$array = ASCII::charsArrayWithSingleLanguageValues();
$tmpKey = \array_search('hnaik', $array['replace']);
echo $array['orig'][$tmpKey]; // '၌'

Parameters:

  • bool $replace_extra_symbols [optional] Add some more replacements e.g. "£" with " pound ".
  • bool $asOrigReplaceArray [optional] TRUE === return {orig: string[], replace: string[]} array

Return:

  • array An array of replacements.

clean(string $str, bool $normalize_whitespace, bool $keep_non_breaking_space, bool $normalize_msword, bool $remove_invisible_characters): string

↑
Accepts a string and removes all non-UTF-8 characters from it + extras if needed.

Parameters:

  • string $str The string to be sanitized.
  • bool $normalize_whitespace [optional] Set to true, if you need to normalize the whitespace.
  • bool $keep_non_breaking_space [optional] Set to true, to keep non-breaking-spaces, in combination with $normalize_whitespace
  • bool $normalize_msword [optional] Set to true, if you need to normalize MS Word chars e.g.: "…" => "..."
  • bool $remove_invisible_characters [optional] Set to false, if you not want to remove invisible characters e.g.: "\0"

Return:

  • string A clean UTF-8 string.

getAllLanguages(): string[]

↑
Get all languages from the constants "ASCII::.*LANGUAGE_CODE".

Parameters:
nothing

Return:

  • string[]

is_ascii(string $str): bool

↑
Checks if a string is 7 bit ASCII.

EXAMPLE:
ASCII::is_ascii('白'); // false

Parameters:

  • string $str The string to check.

Return:

  • bool **true** if it is ASCII **false** otherwise

normalize_msword(string $str): string

↑
Returns a string with smart quotes, ellipsis characters, and dashes from
Windows-1252 (commonly used in Word documents) replaced by their ASCII
equivalents.

EXAMPLE:
ASCII::normalize_msword('„Abcdef…”'); // '"Abcdef..."'

Parameters:

  • string $str The string to be normalized.

Return:

  • string A string with normalized characters for commonly used chars in Word documents.

normalize_whitespace(string $str, bool $keepNonBreakingSpace, bool $keepBidiUnicodeControls, bool $normalize_control_characters): string

↑
Normalize the whitespace.

EXAMPLE:
ASCII::normalize_whitespace("abc-\xc2\xa0-öäü-\xe2\x80\xaf-\xE2\x80\xAC", true); // "abc-\xc2\xa0-öäü- -"

Parameters:

  • string $str The string to be normalized.
  • bool $keepNonBreakingSpace [optional] Set to true, to keep non-breaking-spaces.
  • bool $keepBidiUnicodeControls [optional] Set to true, to keep non-printable (for the web) bidirectional text chars.
  • bool $normalize_control_characters [optional] Set to true, to convert e.g. LINE-, PARAGRAPH-SEPARATOR with "\n" and LINE TABULATION with "\t".

Return:

  • string A string with normalized whitespace.

remove_invisible_characters(string $str, bool $url_encoded, string $replacement, bool $keep_basic_control_characters): string

↑
Remove invisible characters from a string.

e.g.: This prevents sandwiching null characters between ascii characters, like Java\0script.

copy&past from https://github.com/bcit-ci/CodeIgniter/blob/develop/system/core/Common.php

Parameters:

  • string $str
  • bool $url_encoded
  • string $replacement
  • bool $keep_basic_control_characters

Return:

  • string

to_ascii(string $str, string $language, bool $remove_unsupported_chars, bool $replace_extra_symbols, bool $use_transliterate, bool|null $replace_single_chars_only): string

↑
Returns an ASCII version of the string. A set of non-ASCII characters are
replaced with their closest ASCII counterparts, and the rest are removed
by default. The language or locale of the source string can be supplied
for language-specific transliteration in any of the following formats:
en, en_GB, or en-GB. For example, passing "de" results in "äöü" mapping
to "aeoeue" rather than "aou" as in other languages.

EXAMPLE:
ASCII::to_ascii('�Düsseldorf�', 'en'); // Dusseldorf

Parameters:

  • string $str The input string.
  • string $language [optional] Language of the source string. (default is 'en') | ASCII::*_LANGUAGE_CODE
  • bool $remove_unsupported_chars [optional] Whether or not to remove the unsupported characters.
  • bool $replace_extra_symbols [optional] Add some more replacements e.g. "£" with " pound ".
  • bool $use_transliterate [optional] Use ASCII::to_transliterate() for unknown chars.
  • bool|null $replace_single_chars_only [optional] Single char replacement is better for the performance, but some languages need to replace more then one char at the same time. | NULL === auto-setting, depended on the language

Return:

  • string A string that contains only ASCII characters.

to_filename(string $str, bool $use_transliterate, string $fallback_char): string

↑
Convert given string to safe filename (and keep string case).

EXAMPLE:
ASCII::to_filename('שדגשדג.png', true)); // 'shdgshdg.png'

Parameters:

  • string $str
  • bool $use_transliterate ASCII::to_transliterate() is used by default - unsafe characters are simply replaced with hyphen otherwise.
  • string $fallback_char

Return:

  • string A string that contains only safe characters for a filename.

to_slugify(string $str, string $separator, string $language, string[] $replacements, bool $replace_extra_symbols, bool $use_str_to_lower, bool $use_transliterate): string

↑
Converts the string into an URL slug. This includes replacing non-ASCII
characters with their closest ASCII equivalents, removing remaining
non-ASCII and non-alphanumeric characters, and replacing whitespace with
$separator. The separator defaults to a single dash, and the string
is also converted to lowercase. The language of the source string can
also be supplied for language-specific transliteration.

Parameters:

  • string $str
  • string $separator [optional] The string used to replace whitespace.
  • string $language [optional] Language of the source string. (default is 'en') | ASCII::*_LANGUAGE_CODE
  • array<string, string> $replacements [optional] A map of replaceable strings.
  • bool $replace_extra_symbols [optional] Add some more replacements e.g. "£" with " pound ".
  • bool $use_str_to_lower [optional] Use "string to lower" for the input.
  • bool $use_transliterate [optional] Use ASCII::to_transliterate() for unknown chars.

Return:

  • string A string that has been converted to an URL slug.

to_transliterate(string $str, string|null $unknown, bool $strict): string

↑
Returns an ASCII version of the string. A set of non-ASCII characters are
replaced with their closest ASCII counterparts, and the rest are removed
unless instructed otherwise.

EXAMPLE:
ASCII::to_transliterate('déjà σσς iıii'); // 'deja sss iiii'

Parameters:

  • string $str The input string.
  • string|null $unknown [optional] Character use if character unknown. (default is '?') But you can also use NULL to keep the unknown chars.
  • bool $strict [optional] Use "transliterator_transliterate()" from PHP-Intl

Return:

  • string A String that contains only ASCII characters.

Unit Test

  1. Composer is a prerequisite for running the tests.
text
composer install
  1. The tests can be executed by running this command from the root directory:
bash
./vendor/bin/phpunit

Support

For support and donations please visit Github | Issues | PayPal | Patreon.

For status updates and release announcements please visit Releases | Twitter | Patreon.

For professional support please contact me.

Thanks

  • Thanks to GitHub (Microsoft) for hosting the code and a good infrastructure including Issues-Managment, etc.
  • Thanks to IntelliJ as they make the best IDEs for PHP and they gave me an open source license for PhpStorm!
  • Thanks to Travis CI for being the most awesome, easiest continous integration tool out there!
  • Thanks to StyleCI for the simple but powerful code style check.
  • Thanks to PHPStan && Psalm for really great Static analysis tools and for discover bugs in the code!

Released under the MIT License - see LICENSE.txt for details.


Vendor Doctrine Inflector Docs En Index (`vendor/doctrine/inflector/docs/en/index.rst`)

Introduction

The Doctrine Inflector has methods for inflecting text. The features include pluralization,
singularization, converting between camelCase and under_score and capitalizing
words.

Installation

You can install the Inflector with composer:

.. code-block:: console

text
$ composer require doctrine/inflector

Usage

Using the inflector is easy, you can create a new Doctrine\Inflector\Inflector instance by using
the Doctrine\Inflector\InflectorFactory class:

.. code-block:: php

text
use Doctrine\Inflector\InflectorFactory;

$inflector = InflectorFactory::create()->build();

By default it will create an English inflector. If you want to use another language, just pass the language
you want to create an inflector for to the createForLanguage() method:

.. code-block:: php

text
use Doctrine\Inflector\InflectorFactory;
use Doctrine\Inflector\Language;

$inflector = InflectorFactory::createForLanguage(Language::SPANISH)->build();

The supported languages are as follows:

  • Language::ENGLISH
  • Language::FRENCH
  • Language::NORWEGIAN_BOKMAL
  • Language::PORTUGUESE
  • Language::SPANISH
  • Language::TURKISH

If you want to manually construct the inflector instead of using a factory, you can do so like this:

.. code-block:: php

text
use Doctrine\Inflector\CachedWordInflector;
use Doctrine\Inflector\RulesetInflector;
use Doctrine\Inflector\Rules\English;

$inflector = new Inflector(
    new CachedWordInflector(new RulesetInflector(
        English\Rules::getSingularRuleset()
    )),
    new CachedWordInflector(new RulesetInflector(
        English\Rules::getPluralRuleset()
    ))
);

Adding Languages

If you are interested in adding support for your language, take a look at the other languages defined in the
Doctrine\Inflector\Rules namespace and the tests located in Doctrine\Tests\Inflector\Rules. You can copy
one of the languages and update the rules for your language.

Once you have done this, send a pull request to the doctrine/inflector repository with the additions.

Custom Setup

If you want to setup custom singular and plural rules, you can configure these in the factory:

.. code-block:: php

text
use Doctrine\Inflector\InflectorFactory;
use Doctrine\Inflector\Rules\Pattern;
use Doctrine\Inflector\Rules\Patterns;
use Doctrine\Inflector\Rules\Ruleset;
use Doctrine\Inflector\Rules\Substitution;
use Doctrine\Inflector\Rules\Substitutions;
use Doctrine\Inflector\Rules\Transformation;
use Doctrine\Inflector\Rules\Transformations;
use Doctrine\Inflector\Rules\Word;

$inflector = InflectorFactory::create()
    ->withSingularRules(
        new Ruleset(
            new Transformations(
                new Transformation(new Pattern('/^(bil)er$/i'), '\1'),
                new Transformation(new Pattern('/^(inflec|contribu)tors$/i'), '\1ta')
            ),
            new Patterns(new Pattern('singulars')),
            new Substitutions(new Substitution(new Word('spins'), new Word('spinor')))
        )
    )
    ->withPluralRules(
        new Ruleset(
            new Transformations(
                new Transformation(new Pattern('^(bil)er$'), '\1'),
                new Transformation(new Pattern('^(inflec|contribu)tors$'), '\1ta')
            ),
            new Patterns(new Pattern('noflect'), new Pattern('abtuse')),
            new Substitutions(
                new Substitution(new Word('amaze'), new Word('amazable')),
                new Substitution(new Word('phone'), new Word('phonezes'))
            )
        )
    )
    ->build();

No operation inflector

The Doctrine\Inflector\NoopWordInflector may be used to configure an inflector that doesn't perform any operation for
pluralization and/or singularization. If will simply return the input as output.

This is an implementation of the Null Object design pattern <https://sourcemaking.com/design_patterns/null_object>_.

.. code-block:: php

text
use Doctrine\Inflector\Inflector;
use Doctrine\Inflector\NoopWordInflector;

$inflector = new Inflector(new NoopWordInflector(), new NoopWordInflector());

Tableize

Converts ModelName to model_name:

.. code-block:: php

text
echo $inflector->tableize('ModelName'); // model_name

Classify

Converts model_name to ModelName:

.. code-block:: php

text
echo $inflector->classify('model_name'); // ModelName

Camelize

This method uses Classify_ and then converts the first character to lowercase:

.. code-block:: php

text
echo $inflector->camelize('model_name'); // modelName

Capitalize

Takes a string and capitalizes all of the words, like PHP's built-in
ucwords function. This extends that behavior, however, by allowing the
word delimiters to be configured, rather than only separating on
whitespace.

Here is an example:

.. code-block:: php

text
$string = 'top-o-the-morning to all_of_you!';

echo $inflector->capitalize($string); // Top-O-The-Morning To All_of_you!

echo $inflector->capitalize($string, '-_ '); // Top-O-The-Morning To All_Of_You!

Pluralize

Returns a word in plural form.

.. code-block:: php

text
echo $inflector->pluralize('browser'); // browsers

Singularize

Returns a word in singular form.

.. code-block:: php

text
echo $inflector->singularize('browsers'); // browser

Urlize

Generate a URL friendly string from a string of text:

.. code-block:: php

text
echo $inflector->urlize('My first blog post'); // my-first-blog-post

Unaccent

You can unaccent a string of text using the unaccent() method:

.. code-block:: php

text
echo $inflector->unaccent('año'); // ano

Legacy API

The API present in Inflector 1.x is still available, but will be deprecated in a future release and dropped for 3.0.
Support for languages other than English is available in the 2.0 API only.

Acknowledgements

The language rules in this library have been adapted from several different sources, including but not limited to:

  • Ruby On Rails Inflector <http://api.rubyonrails.org/classes/ActiveSupport/Inflector.html>_
  • ICanBoogie Inflector <https://github.com/ICanBoogie/Inflector>_
  • CakePHP Inflector <https://book.cakephp.org/3.0/en/core-libraries/inflector.html>_

--- METRICS ---