mfonte / base62x
A Base62x PHP实现库,可用于Laravel等框架中,支持字符串、数组、对象和二进制资源的编码/解码。它还支持Gzip压缩/解压缩和对称加密。
Requires
- php: >=7.2
Requires (Dev)
- friendsofphp/php-cs-fixer: ^3.4
- orchestra/testbench: ^3.5.6
- php-coveralls/php-coveralls: ^2.5.3
- phpstan/phpstan: ^1.9
- phpunit/phpunit: ^8
README
此库可用于将字符串编码为 Base62x 格式。
此存储库采用了 Base62x 的参考实现: https://github.com/wadelau/Base62x
声明原始作者存储库,Base62x 是一种替代 Base 64 的方法,输出中没有符号。
Base62x 是一种 非符号 Base64 编码方案。它可以在计算机文件系统、编程语言数据交换、互联网通信系统等场景中安全使用,并且是许多 Base64 编码方案变体的理想替代品和继承者。
此存储库是围绕 wadelau/Base62x 存储库的包装,专门为PHP设计,并支持composer。
它可以集成到任何框架中,如Laravel,以实现开箱即用的 Base62x 支持。
安装
非常简单。
composer require mfonte/base62x
所需环境
- PHP >= 7.2
gzip模块,用于gzip压缩支持openssl模块,用于加密支持
用例
Base64在GET字符串中使用臭名昭著。使用此库,您可以安全地编码(并压缩)并通过GET参数传递数据。
另一个用例是当您需要从一台服务器将二进制数据发送到另一台服务器时。
许多Apache模块(如Mod Security)在服务器到服务器通信中传递原始二进制数据或复杂操作时会做一些奇怪的事情。
当然,您可以在两端使用原生的 base64_encode() 和 base64_decode(),但使用此库不仅您在编码数据,您还可以在途中压缩和加密它!
基本用法
使用非常简单,具有优雅的API
<?php use Mfonte\Base62x\Base62x; $string = 'this is some string that needs to be encoded'; $encoded = Base62x::encode($string)->get(); $decoded = Base62x::decode($encoded)->get();
真实用例场景
一个有用的真实用例场景示例,我在一些项目中使用过,是将json上下文数据从HTML页面传递到Ajax工作程序。
<?php // create an ajaxToken to be included in the <head> of the document $encryptedAjaxToken = Base62x::encode('secure_ajax_token')->encrypt(config('app.key'))->compress()->get(); // create a context of data to be passed to the Ajax worker $contextData = ['route' => 'homepage', 'pagination' => ['currPage' => 1, 'maxPages' => 2]]; $encryptedContextData = Base62x::encode($contextData)->encrypt(config('app.key'))->compress()->get(); $html = <<<EOT <head> <meta charset="utf-8"> ... ... <script type="text/javascript"> const ajaxConfig = { url: 'https://www.example.com/ajaxRequest', token: '$encryptedAjaxToken', context: '$encryptedContextData' }; function ajaxRequest() { $.post(ajaxConfig.url, Object.assign({ method: "whatever", }, ajaxConfig)).done(function(response) { // logic }); } </script> </head> EOT;
从前端到Ajax后端的数据生命周期完全加密,并且不会破坏HTML结构,因为Base62x字符串基于一个与嵌入到普通JS字符串中兼容的字母表,就像我在提供的示例中所展示的那样。
在Ajax后端您可以验证令牌,收集上下文数据,并且只有当设置正确时才回复
<?php try { $ajaxToken = (array_key_exists('token', $_POST)) ? $_POST['token'] : ''; $context = (array_key_exists('context', $_POST)) ? $_POST['context'] : ''; $decodedAjaxToken = Base62x::decode($ajaxToken)->decrypt(config('app.key'))->get(); $decodedContext = Base62x::decode($context)->decrypt(config('app.key'))->get(); if($ajaxToken === 'secure_ajax_token' && is_array($context)) { // checks are OK, proceed with your logic } // fallback: handle not authorized header("HTTP/1.1 401 Unauthorized"); echo json_encode(['status' => false, 'error' => 401]); }
此库支持二进制流
这意味着您可以编码二进制数据,例如原始JPEG或原始音频文件。
<?php use Mfonte\Base62x\Base62x; use GuzzleHttp\Client; // on one machine $payload = file_get_contents('a_nice_image.jpg'); $encoded_payload = Base62x::encode($payload)->get(); $client = new Client(['base_uri' => 'https://example.com/']); $response = $client->post('postRequest/', [ 'form_params' => [ 'encoded_image' => $encoded_payload ] ]); ... // on another machine $encoded_payload = $request->get('encoded_image'); $image = Base62x::decode($encoded_payload)->get(); file_put_contents($image, 'a_nice_image_clone.jpg');
此库支持压缩的Base62x编码!
在Base62x编码的同时,您还可以压缩有效载荷。
如果您计划通过GET或POST请求发送大数组或大量数据,这特别有用,您需要确保它不会在不同机器之间或从一个URL到另一个URL时触发错误。
重要提示:在解码和解压缩时,您不需要指定原始压缩算法,因为此信息已保存在编码有效载荷开头的“魔术字符串”中。因此,如果您无法控制可能结束在您的有效载荷上的另一台机器,您不需要担心与对方沟通您实际使用的压缩类型。decode()方法会自动处理。
<?php use Mfonte\Base62x\Base62x; $payload = ['foo' => 'bar', 'bar' => ['foo1', 'foo2', 'foo3', 'fooman' => 'foobar'], 'barfoo' => [1,2,3,4,5,6,7,8,9,10]]; try { $encoded_payload = Base62x::encode($payload)->compress()->get(); } catch(Exception $ex) { // One Exception of Mfonte/Base62x/Exception/EncodeException // or Mfonte/Base62x/Exception/InvalidParam // or Mfonte/Base62x/Exception/CompressionException } $final_url = 'https://example.com/decodetest/?data=' . $encoded_payload; ... // on the "decodetest" url ... $encoded_payload = (array_key_exists('data', $_GET) && strlen($_GET['data'])) ? $_GET['data'] : null; if(!empty($encoded_payload)) { try { // in the $decoded variable, you'll automagically get the original Array $decoded = Base62x::decode($encoded_payload)->get(); } catch(Exception $ex) { // One Exception of Mfonte/Base62x/Exception/DecodeException or Mfonte/Base62x/Exception/InvalidParam } }
可用的压缩方法
- gzip,编码为
zlib、deflate或gzip。如果没有进一步指示,compress()方法默认为gzip/zlib - Huffman 通过专用的 PHP Huffman 实现。**请注意,此压缩方法目前无法正常工作,请在生产环境中不要使用它**。
这些参数可以按照如下方式传递给 compress() 方法
<?php use Mfonte\Base62x\Base62x; $payload = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.'; try { $gzip_default = Base62x::encode($payload)->compress()->get(); // alias of compress('gzip', 'gzip') $gzip_gzip_encoded = Base62x::encode($payload)->compress('gzip', 'gzip')->get(); $gzip_zlib_encoded = Base62x::encode($payload)->compress('gzip', 'zlib')->get(); $gzip_deflate_encoded = Base62x::encode($payload)->compress('gzip', 'deflate')->get(); // you DON'T NEED to call decompress() because the compression method is "saved" inside the // encoded payload into a "magic string" $decoded = Base62x::decode($gzip_default)->get(); } catch(Exception $ex) { // One Exception of Mfonte/Base62x/Exception/EncodeException // or Mfonte/Base62x/Exception/InvalidParam // or Mfonte/Base62x/Exception/CompressionException }
加密
从版本 1.2 开始,此库支持 **加密**。
加密可以与压缩 **串联**。
<?php use Mfonte\Base62x\Base62x; $payload = 'my_payload'; $key = 'a_very_secret_string'; try { $encoded_and_crypted = Base62x::encode($payload)->encrypt($key)->get(); $encoded_and_compressed_and_crypted = Base62x::encode($payload)->encrypt($key)->compress()->get(); // to perform decryption, you must pass in the original $key $decrypted = Base62x::decode($payload)->decrypt($key)->get(); } catch(Exception $ex) { // One Exception of Mfonte/Base62x/Exception/EncodeException // or Mfonte/Base62x/Exception/InvalidParam // or Mfonte/Base62x/Exception/CompressionException // or Mfonte/Base62x/Exception/CryptException }
测试
简单地在此模块的安装目录下运行 composer install。
然后,运行 composer test 以运行所有测试。
一些测试 **可能失败**,因为 testEncodingWithAllAvailableEncryptionAlgorithms 会检查您环境中安装的所有可用的 openssl_get_cipher_methods()。一个可能的失败例子是:加密方法 "id-aes128-CCM" 在您的 PHP 安装中不受支持或不是一个有效的加密算法。
待办事项
- 修复 Huffman 压缩
- 添加 Bzip2 压缩
贡献
如果您想为此项目做出贡献,请使用 php-cs-fixer 将您的代码格式化为 PSR 标准,并遵循此存储库中提供的配置文件 .php-cs-fixer.dist.php 中指定的规则。谢谢!
感谢
非常感谢 wadelau [Wade Lau 在 ufqi.com] 实现了如此有用的编码模式。