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();
}

- 阅读剩余部分 -

Bootstrap V4 实现自动下拉菜单

1. 前言

现在网 原创,换成 Bootstrap V4 后,好多在 Bootstrap V3 能用 JavaScript 实现的效果都变了,暂时未在官方文档找到 JavaScript 插件 的用法,只能自己乱搞一下了

2. 使用 JavaScript 实现

2-1. 需引入 Bootstrap V4bootstrap.jsbootstrap.min.js(压缩版) 和 jQuery.js

JavaScript 代码如下:

$('li.nav-item.dropdown').mouseover(function() {
    /*当鼠标经过时下拉(打开)*/
    $(this).addClass('show');
    $(this).children([2]).addClass('show');
}).mouseout(function() {
    /*当鼠标离开时时合起(关闭)*/
    $(this).removeClass('show');
    $(this).children([2]).removeClass('show');
});

效果图:

QQ截图20180610164616.png

3. 实例

粘贴就可以查看效果了
HTML 在线运行:http://www.runoob.com/runcode

<!doctype html>
<html lang="zh-CN">
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
        <meta name="description" content="现在工具网">
        <meta name="author" content="陈文州">

        <title>现在工具网</title>
        <link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.1.0/css/bootstrap.min.css" rel="stylesheet">
    </head>
    <body>

        <nav class="navbar navbar-expand-md navbar-dark fixed-top bg-dark">
            <a class="navbar-brand" href="#">现在工具网</a>
            <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarsDefault" aria-controls="navbarsExampleDefault" aria-expanded="false" aria-label="Toggle navigation">
                <span class="navbar-toggler-icon"></span>
            </button>

            <div class="collapse navbar-collapse" id="navbarsDefault">
                <ul class="navbar-nav mr-auto">
                    <li class="nav-item active">
                        <a class="nav-link" href="./">首页</a>
                    </li>
                    <li class="nav-item">
                        <a class="nav-link" href="/login">登陆账号</a>
                    </li>
                    <li class="nav-item">
                        <a class="nav-link" href="/register">注册账号</a>
                    </li>
                    <li class="nav-item dropdown">
                        <a class="nav-link dropdown-toggle" href="" id="more_website" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">旗下网站</a>
                        <div class="dropdown-menu" aria-labelledby="more_website">
                            <a class="dropdown-item" href="https://nowtime.cc" target="_blank">现在网|个人博客</a>
                            <a class="dropdown-item" href="https://nowtool.cn" target="_blank">现在工具网</a>
                        </div>
                    </li>
                    <li class="nav-item dropdown">
                        <a class="nav-link dropdown-toggle" href="" id="more_website" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">旗下网站</a>
                        <div class="dropdown-menu" aria-labelledby="more_website">
                            <a class="dropdown-item" href="https://nowtime.cc" target="_blank">现在网|个人博客</a>
                            <a class="dropdown-item" href="https://nowtool.cn" target="_blank">现在工具网</a>
                        </div>
                    </li>
                </ul>
                <form class="form-inline my-2 my-lg-0">
                    <input class="form-control mr-sm-2" type="text" placeholder="Search" aria-label="Search">
                    <button class="btn btn-outline-success my-2 my-sm-0" type="submit">Search</button>
                </form>
            </div>
        </nav>


        <script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
        <script src="https://cdn.bootcss.com/bootstrap/4.1.0/js/bootstrap.min.js"></script>
        <script>
            $('li.nav-item.dropdown').mouseover(function() {
                /*当鼠标经过时下拉(打开)*/
                $(this).addClass('show');
                $(this).children([2]).addClass('show');
            }).mouseout(function() {
                /*当鼠标离开时时合起(关闭)*/
                $(this).removeClass('show');
                $(this).children([2]).removeClass('show');
            });
        </script>
    </body>
</html>

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错误实例


- 阅读剩余部分 -