分类 PHP 下的文章

PHP 浮点数精确运算

bc 是 Binary Calculator 的缩写。bc* 函数的参数都是操作数加上一个可选的 [int scale],比如 string bcadd(string $left_operand, string $right_operand[, int $scale]),如果scale没有提供,就用 bcscale 的缺省值。这里大数直接用一个由 0-9 组成的 string 表示,计算结果返回的也是一个 string

PHP函数作用
bcadd将两个高精度数字相加
bccomp比较两个高精度数字,返回-1, 0, 1
bcdiv将两个高精度数字相除
bcmod求高精度数字余数
bcmul将两个高精度数字相乘
bcpow求高精度数字乘方
bcpowmod求高精度数字乘方求模,数论里非常常用
bcscale配置默认小数点位数,相当于就是 Linux bc 中的 scale=
bcsqrt求高精度数字平方根
bcsub将两个高精度数字相减

首先看一段代码:

<?php
$a = 0.1;
$b = 0.7;
var_dump(($a + $b) == 0.8);

打印出来的值居然为 bool(false)

这是为啥?PHP手册对于浮点数有以下警告信息:

Warning:浮点数精度
显然简单的十进制分数如同 0.10.7 不能在不丢失一点点精度的情况下转换为内部二进制的格式。这就会造成混乱的结果:例如,floor((0.1+0.7)*10) 通常会返回 7 而不是预期中的 8,因为该结果内部的表示其实是类似 7.9999999999...

这和一个事实有关,那就是不可能精确的用有限位数表达某些十进制分数。例如,十进制的 1/3 变成了 0.3333333...

所以永远不要相信浮点数结果精确到了最后一位,也永远不要比较两个浮点数是否相等。如果确实需要更高的精度,应该使用任意精度数学函数或者 gmp 函数

那么上面的算式我们应该改写为:

<?php
$a = 0.1;
$b = 0.7;
var_dump(bcadd($a,$b,2) == 0.8);

这样就能解决浮点数的计算问题了

转自:http://blog.163.com/lisoaring@126/blog/static/19205606201123010184107/

PHPJiaMi 免扩展加密分析及解密

0x00 前言

前几天去玩了 pwnhub 公开赛的题目,源码下载之后发现是 PHPJiaMi 加密。之前有分析过 phpjm 加密并写出过解密文件,所以研究下这个 PHPJiaMi。
PHP 免扩展加密的主流加密方法采用了 ascii 码 129-255 的乱码来实现变量名、函数名混淆,编辑器打开后就是一堆乱码,造成不可读。

加密流程:源码 -> 加密处理(压缩,替换,BASE64,转义)-> 安全处理(验证文件 MD5 值,限制 IP、限域名、限时间、防破解、防命令行调试)-> 加密程序成品,再简单的说:源码 + 加密外壳 == 加密程序 (该段出处)

0x01 解密准备

这里做演示,我写了 phpinfo() 然后去 http://www.phpjiami.com/ 生成加密文件,打开之后,果然都是一片乱码。
使用代码修复工具 http://zhaoyuanma.com/phpcodefix.html 将 ascii 不可见字符的变量修复成正常的变量名,再 PHP 代码美化,方便下一步分析。



- 阅读剩余部分 -

PHP libcurl 封装异步并发 HTTP 客户端

PHP 标准库内置 curl 扩展,不过实现不完整,如 multi_socket_action 接口。

无意中发现 pecl http 库同样基于 libcurl 封装,支持更多的libcurl特性,更新也比较快,底层通过 libevent(epoll) 实现 multi_socket_action 接口。

不过 pecl http 版本1和版本2 api完全不兼容,使用过程中稳定性及性能并不如PHP内置的curl,好像还有内存泄露,以下为示例代码,基于 pecl_http 2.20

<?php
function push($client, $url) {
  $req = new http\Client\Request("GET", $url, ["User-Agent"=>"My Client/0.1"]);
  $req->setOptions(array('connecttimeout'=>1, 'timeout'=>1));
  $client->enqueue($req, function($response) use ($client, $req, $url) {
     printf("%s returned '%s' (%d)\n", $response->getTransferInfo("effective_url"), $response->getInfo(), $response->getResponseCode());
     echo $client->count().PHP_EOL;
     global $urls;
     if ($urls) {
        while ($client->count() < 20) {
           $url = array_shift($urls);
           push($client, $url);
        }
        return true; // dequeue
     }
  });
}

$client = new http\Client;
$client->enablePipelining(true);
$client->enableEvents(true);

for ($i = 0; $i < 10000; ++$i) {
  $urls[] = "http://192.168.1.3/";
}
for ($i = 0; $i < 20; ++$i) {
  $url = array_shift($urls);
  push($client, $url);
}
/*
try{
  var_dump($client->send());
}
catch(http\Exception\RuntimeException  $e)
{
  echo 'Message: ' .$e->getMessage().PHP_EOL;
}
*/

while ($client->once()) {
  $client->wait();
}

- 阅读剩余部分 -

PHP curl_errno 错误码(大全)说明附错误示例

接上一篇:中文cURL 错误码(error code)对照表
主要是自己有项目需求做的,,下面有 PHP cURL错误实例,代码可能写的不咋地,有错误欢迎指正!

<?php
$error_codes_chinese = array(
  '0' => '一切都好。照常进行。',
  '1' => '您传递给 libcurl 的 URL 使用此 libcurl 不支持的协议。支持可能是您没有使用的编译时选项,它可能是拼写错误的协议字符串,或者仅仅是 libcurl 没有代码的协议。',
  '2' => '非常早的初始化代码失败。这可能是一个内部错误或问题,或者是在初始阶段根本无法完成的资源问题。',
  '3' => '该网址格式不正确。',
  '4' => '由于构建时间的决定,未在此 libcurl 中找到内置的请求的功能,协议或选项。这意味着在构建 libcurl 时没有启用或显式禁用某个功能或选项,并且为了使其功能得到重建的 libcurl。',
  '5' => '无法解析代理。给定的代理主机无法解析。',
  '6' => '无法解析主机。给定的远程主机未解决。',
  '7' => '无法连接到主机或代理。',
  '8' => '服务器发送的数据 libcurl 无法解析。此错误代码不仅用于 FTP,而且自 7.51.0 起用作 CURLE_WEIRD_SERVER_REPLY。',
  '9' => '我们被拒绝访问URL中给出的资源。对于FTP,尝试更改到远程目录时会发生这种情况。',
  '10' => '在使用活动的FTP会话时等待服务器连接回来时,通过控制连接或类似的方式发送了错误代码。',
  '11' => '在将FTP密码发送到服务器之后,libcurl 需要一个正确的回复。此错误代码表示已返回意外的代码。',
  '12' => '在等待服务器连接的活动 FTP 会话期间,CURLOPT_ACCEPTTIMEOUT_MS(或内部默认值)超时已过期',
  '13' => '作为对 PASV 或 EPSV 命令的响应,libcurl 无法从服务器获得明智的结果。服务器有缺陷',
  '14' => 'FTP 服务器返回一个 227 行作为对 PASV 命令的响应。如果 libcurl 无法解析该行,则返回此代码。',
  '15' => '查找用于新连接的主机的内部故障。',
  '16' => '在 HTTP2 成帧层中检测到问题。这有点通用,可能是几个问题之一,详情请参阅错误缓冲区。',
  '17' => '尝试将传输模式设置为二进制或ASCII时收到错误。',
  '18' => '文件传输比预期更短或更大。当服务器首次报告预期的传输大小,然后传递与先前给定的大小不匹配的数据时,会发生这种情况。',
  '19' => '这是对 \'RETR\' 命令的一个奇怪的回复或零字节传输完成。',
  '21' => '向远程服务器发送自定义 \'QUOTE\' 命令时,其中一个命令返回了 400 或更高(对于FTP)的错误代码,或者以其他方式表示该命令未成功完成。',
  '22' => '如果 CURLOPT_FAILONERROR 设置为 TRUE,并且 HTTP 服务器返回 >=400 的错误代码,则返回此值。',
  '23' => '将接收到的数据写入本地文件时发生错误,或者从写入回调中将错误返回给 libcurl。',
  '25' => '开始上传失败。对于 FTP,服务器通常拒绝 STOR 命令。错误缓冲区通常包含服务器对此的解释。',
  '26' => '读取本地文件时出现问题或读取回调返回错误。',
  '27' => '内存分配请求失败。这是严重的不良情况,如果这种情况发生,事情就会严重破坏。',
  '28' => '操作超时。根据条件达到指定的超时期限。',
  '30' => 'FTP PORT命令返回错误。这种情况通常发生在您未指定足够好的地址供 libcurl 使用时。请参阅 CURLOPT_FTPPORT。',
  '31' => 'FTP REST 命令返回错误。如果服务器健全,这绝不应该发生。',
  '33' => '服务器不支持或接受范围请求。',
  '34' => '这是一个奇怪的错误,主要是由于内部的困惑而发生的。',
  '35' => 'SSL/TLS 握手中发生了问题。您确实需要错误缓冲区并在那里读取消息,因为它稍微查明了问题。可能是证书(文件格式、路径、权限)、密码等原因。',
  '36' => '由于指定的偏移超出了文件边界,下载无法恢复。',
  '37' => '用 file:// 给出的文件无法打开。很可能是因为文件路径不能识别现有文件。你检查文件权限吗?',
  '38' => 'LDAP 不能绑定。LDAP 绑定操作失败。',
  '39' => 'LDAP 搜索失败。',
  '41' => '找不到功能。找不到所需的 zlib 功能。',
  '42' => '回调中止。回调函数返回 \'abort\' 给 libcurl。',
  '43' => '内部错误。一个函数被调用了一个错误的参数。',
  '45' => '接口错误。指定的传出接口不能使用。使用 CURLOPT_INTERFACE 设置传出连接的源 IP 地址使用哪个接口。',
  '47' => '太多的重定向。当跟随重定向时,libcurl 达到最大量。用 CURLOPT_MAXREDIRS 设置你的限制。',
  '48' => '传递给 libcurl 的选项无法识别/已知。请参阅相应的文档。这在使用 libcurl 的程序中很可能是一个问题。错误缓冲区可能包含更多关于哪个确切选项的具体信息。',
  '49' => '一个 telnet 选项字符串被非法格式化。',
  '51' => '远程服务器的 SSL 证书或 SSH md5 指纹被视为不正确。',
  '52' => '没有任何东西从服务器返回,并且在这种情况下,什么都不会被认为是错误。',
  '53' => '未找到指定的加密引擎。',
  '54' => '无法将选定的SSL加密引擎设置为默认值!',
  '55' => '发送网络数据失败。',
  '56' => '接收网络数据失败。',
  '58' => '与本地客户端证书有关的问题。',
  '59' => '无法使用指定的密码。',
  '60' => '对等证书不能用已知的 CA 证书进行认证。',
  '61' => '无法识别的传输编码。',
  '62' => '无效的 LDAP 网址。',
  '63' => '超过最大文件大小。',
  '64' => '请求的 FTP SSL 级别失败。',
  '65' => '当执行发送操作时,cURL 不得不倒带数据以重传,但倒带操作失败。',
  '66' => '启动 SSL 引擎失败。',
  '67' => '远程服务器拒绝 cURL 登录(在7.13.1中添加)',
  '68' => '在 TFTP 服务器上找不到文件。',
  '69' => 'TFTP 服务器上的权限问题。',
  '70' => '服务器上的磁盘空间不足。',
  '71' => '非法 TFTP 操作。',
  '72' => '未知的 TFTP 传输标识。',
  '73' => '文件已经存在,不会被覆盖。',
  '74' => '这个错误不应该由正常运行的 TFTP 服务器返回。',
  '75' => '字符转换失败。',
  '76' => '呼叫者必须注册转换回调。',
  '77' => '读取 SSL CA 证书时遇到问题(路径访问权限?)',
  '78' => 'URL 中引用的资源不存在。',
  '79' => 'SSH 会话期间发生未指定的错误。',
  '80' => '无法关闭 SSL 连接。',
  '81' => '套接字尚未准备好 发送/接收 等待,直到准备就绪,然后重试。该返回码仅从 curl_easy_recv 和 curl_easy_send 返回(在 7.18.2 中添加)',
  '82' => '无法加载 CRL 文件(在 7.19.0 中添加)',
  '83' => '发卡行检查失败(在 7.19.0 中添加)',
  '84' => 'FTP 服务器完全不理解 PRET 命令,或者不支持给定的参数。使用 CURLOPT_CUSTOMREQUEST 时要小心,自定义 LIST 命令也将在 PASV之 前使用 PRET CMD 发送。(在 7.20.0 中增加)',
  '85' => 'RTSP CSeq 数字不匹配。',
  '86' => 'RTSP 会话标识符不匹配。',
  '87' => '无法解析 FTP 文件列表(在 FTP 通配符下载期间)。',
  '88' => '块回调报告错误。',
  '89' => '(仅供内部使用,不会由 libcurl 返回)没有可用的连接,会话将排队。(在 7.30.0 中增加)',
  '90' => '无法匹配使用 CURLOPT_PINNEDPUBLICKEY 指定的固定键。',
  '91' => '当用 CURLOPT_SSL_VERIFYSTATUS 询问时,状态返回失败。',
  '92' => 'HTTP/2 成帧层中的流错误。',
  '93' => '一个API函数在回调中被调用。'
);

$error_codes = array(
  '0' => 'CURLE_OK',
  '1' => 'CURLE_UNSUPPORTED_PROTOCOL',
  '2' => 'CURLE_FAILED_INIT',
  '3' => 'CURLE_URL_MALFORMAT',
  '4' => 'CURLE_URL_MALFORMAT_USER',
  '5' => 'CURLE_COULDNT_RESOLVE_PROXY',
  '6' => 'CURLE_COULDNT_RESOLVE_HOST',
  '7' => 'CURLE_COULDNT_CONNECT',
  '8' => 'CURLE_FTP_WEIRD_SERVER_REPLY',
  '9' => 'CURLE_REMOTE_ACCESS_DENIED',
  '11' => 'CURLE_FTP_WEIRD_PASS_REPLY',
  '13' => 'CURLE_FTP_WEIRD_PASV_REPLY',
  '14'=>'CURLE_FTP_WEIRD_227_FORMAT',
  '15' => 'CURLE_FTP_CANT_GET_HOST',
  '17' => 'CURLE_FTP_COULDNT_SET_TYPE',
  '18' => 'CURLE_PARTIAL_FILE',
  '19' => 'CURLE_FTP_COULDNT_RETR_FILE',
  '21' => 'CURLE_QUOTE_ERROR',
  '22' => 'CURLE_HTTP_RETURNED_ERROR',
  '23' => 'CURLE_WRITE_ERROR',
  '25' => 'CURLE_UPLOAD_FAILED',
  '26' => 'CURLE_READ_ERROR',
  '27' => 'CURLE_OUT_OF_MEMORY',
  '28' => 'CURLE_OPERATION_TIMEDOUT',
  '30' => 'CURLE_FTP_PORT_FAILED',
  '31' => 'CURLE_FTP_COULDNT_USE_REST',
  '33' => 'CURLE_RANGE_ERROR',
  '34' => 'CURLE_HTTP_POST_ERROR',
  '35' => 'CURLE_SSL_CONNECT_ERROR',
  '36' => 'CURLE_BAD_DOWNLOAD_RESUME',
  '37' => 'CURLE_FILE_COULDNT_READ_FILE',
  '38' => 'CURLE_LDAP_CANNOT_BIND',
  '39' => 'CURLE_LDAP_SEARCH_FAILED',
  '41' => 'CURLE_FUNCTION_NOT_FOUND',
  '42' => 'CURLE_ABORTED_BY_CALLBACK',
  '43' => 'CURLE_BAD_FUNCTION_ARGUMENT',
  '45' => 'CURLE_INTERFACE_FAILED',
  '47' => 'CURLE_TOO_MANY_REDIRECTS',
  '48' => 'CURLE_UNKNOWN_TELNET_OPTION',
  '49' => 'CURLE_TELNET_OPTION_SYNTAX',
  '51' => 'CURLE_PEER_FAILED_VERIFICATION',
  '52' => 'CURLE_GOT_NOTHING',
  '53' => 'CURLE_SSL_ENGINE_NOTFOUND',
  '54' => 'CURLE_SSL_ENGINE_SETFAILED',
  '55' => 'CURLE_SEND_ERROR',
  '56' => 'CURLE_RECV_ERROR',
  '58' => 'CURLE_SSL_CERTPROBLEM',
  '59' => 'CURLE_SSL_CIPHER',
  '60' => 'CURLE_SSL_CACERT',
  '61' => 'CURLE_BAD_CONTENT_ENCODING',
  '62' => 'CURLE_LDAP_INVALID_URL',
  '63' => 'CURLE_FILESIZE_EXCEEDED',
  '64' => 'CURLE_USE_SSL_FAILED',
  '65' => 'CURLE_SEND_FAIL_REWIND',
  '66' => 'CURLE_SSL_ENGINE_INITFAILED',
  '67' => 'CURLE_LOGIN_DENIED',
  '68' => 'CURLE_TFTP_NOTFOUND',
  '69' => 'CURLE_TFTP_PERM',
  '70' => 'CURLE_REMOTE_DISK_FULL',
  '71' => 'CURLE_TFTP_ILLEGAL',
  '72' => 'CURLE_TFTP_UNKNOWNID',
  '73' => 'CURLE_REMOTE_FILE_EXISTS',
  '74' => 'CURLE_TFTP_NOSUCHUSER',
  '75' => 'CURLE_CONV_FAILED',
  '76' => 'CURLE_CONV_REQD',
  '77' => 'CURLE_SSL_CACERT_BADFILE',
  '78' => 'CURLE_REMOTE_FILE_NOT_FOUND',
  '79' => 'CURLE_SSH',
  '80' => 'CURLE_SSL_SHUTDOWN_FAILED',
  '81' => 'CURLE_AGAIN',
  '82' => 'CURLE_SSL_CRL_BADFILE',
  '83' => 'CURLE_SSL_ISSUER_ERROR',
  '84' => 'CURLE_FTP_PRET_FAILED',
  '84' => 'CURLE_FTP_PRET_FAILED',
  '85' => 'CURLE_RTSP_CSEQ_ERROR',
  '86' => 'CURLE_RTSP_SESSION_ERROR',
  '87' => 'CURLE_FTP_BAD_FILE_LIST',
  '88' => 'CURLE_CHUNK_FAILED',
  '89' => 'CURLE_NO_CONNECTION_AVAILABLE',
  '90' => 'CURLE_SSL_PINNEDPUBKEYNOTMATCH',
  '91' => 'CURLE_SSL_INVALIDCERTSTATUS',
  '92' => 'CURLE_HTTP2_STREAM',
  '93' => 'CURLE_RECURSIVE_API_CALL'
);

PHP cURL错误实例


- 阅读剩余部分 -

PHP 删除数组指定key(键)

在数组中删除指定 key(键名) 的元素,可以直接用的 unset

例如:

<?php
$arr = array(
  'id'=>1,
  'name' => 'NowTime',
  'website' => 'https://NowTime.cc'
);

//删除一个 key(键名)
unset($arr['name']);
print_r($arr);//打印数组
/*
输出结果:
Array([id] => 1 [website] => https://NowTime.cc )
*/

/********我是分割线*******/

//删除多个 key(键名)
unset($arr['id'],$arr['name']);
print_r($arr);//打印数组
/*
输出结果:
Array( [website] => https://NowTime.cc )
*/