curl_multi_exec:下载的一些图像丢失了一些数据/流不完整

2024-04-05

我已经实现了一个 PHP 函数,它检查并下载大量图像(> 1'000) - 使用数组传递给它 - 使用 PHPcurl_multi_init() method.

经过几次返工后,因为我得到了 0 字节文件等内容。我现在有一个下载所有图像的解决方案 - 但下载的所有其他图像文件都不完整。

在我看来好像我使用file_put_contents()“太早”,意思是,在使用完全接收到一些图像数据之前curl_multi_exec().

不幸的是,我没有找到任何类似的问题,也没有找到任何适合我的情况的谷歌结果,其中我需要使用curl_multi_exec,但不想使用curl-opt-header检索和保存图像“CURLOPT_FILE".

希望有人能够帮助我了解我所缺少的内容以及为什么我在本地保存了一些损坏的图像。

以下是检索到的损坏图像的一些示例:

这是我传递给 Multi-CURL-Function 的示例数组:

$curl_httpresources = [
        [ 'http://www.gravatar.com/avatar/example?d=mm&r=x&s=427'
        ,'/srv/www/data/images/1_unsplash.jpg' ],
        [ 'http://www.gravatar.com/avatar/example?d=identicon&r=x&s=427'
        ,'/srv/www/data/images/2_unsplash.jpg' ],
        [ 'http://www.gravatar.com/avatar/example?d=monsterid&r=x&s=427'
        ,'/srv/www/data/images/3_unsplash.jpg' ],
        [ 'http://www.gravatar.com/avatar/example?d=wavatar&r=x&s=427'
        ,'/srv/www/data/images/4_unsplash.jpg' ],
        [ 'http://www.gravatar.com/avatar/example?d=retro&r=x&s=427'
        ,'/srv/www/data/images/5_unsplash.jpg' ],
        [ 'http://www.gravatar.com/avatar/example?d=mm&r=x&s=427'
        ,'/srv/www/data/images/6_unsplash.jpg' ],
        [ 'http://www.gravatar.com/avatar/example?d=identicon&r=x&s=427'
        ,'/srv/www/data/images/7_unsplash.jpg' ],
        [ 'http://www.gravatar.com/avatar/example?d=monsterid&r=x&s=427'
        ,'/srv/www/data/images/8_unsplash.jpg' ],
        [ 'http://www.gravatar.com/avatar/example?d=wavatar&r=x&s=427'
        ,'/srv/www/data/images/9_unsplash.jpg' ],
        [ 'http://www.gravatar.com/avatar/example?d=retro&r=x&s=427'
        ,'/srv/www/data/images/10_unsplash.jpg' ],
];

我的 Multi-cURL PHP 函数

现在,对于我当前正在使用的功能 - 并且有点“有效”,除了一些部分下载的文件 - 这是代码:

function cURLfetch(array $resources)
{
    /** Disable PHP timelimit, because this could take a while... */
    set_time_limit(0);

    /** Validate the $resources Array (not empty, null, or alike) */
    $resources_num = count($resources);
    if ( empty($resources) || $resources_num <= 0 ) return false;

    /** Callback-Function for writing data to file */
    $callback = function($resource, $filepath)
    {
        file_put_contents($filepath, $resource);
        /** For Debug only: output <img>-Tag with saved $resource */
        printf('<img src="%s"><br>', str_replace('/srv/www', '', $filepath));
    };

    /**
     * Initialize CURL process for handling multiple parallel requests 
     */
    $curl_instance = curl_multi_init();
    $curl_multi_exec_active = null;
    $curl_request_options = [
                                CURLOPT_USERAGENT => 'PHP-Script/1.0 (+https://website.com/)',
                                CURLOPT_TIMEOUT => 10,
                                CURLOPT_FOLLOWLOCATION => true,
                                CURLOPT_VERBOSE => false,
                                CURLOPT_RETURNTRANSFER => true,
                            ];

    /**
     * Looping through all $resources
     *   $resources[$i][0] = HTTP resource
     *   $resources[$i][1] = Target Filepath
     */
    for ($i = 0; $i < $resources_num; $i++)
    {
        $curl_requests[$i] = curl_init($resources[$i][0]);
        curl_setopt_array($curl_requests[$i], $curl_request_options);
        curl_multi_add_handle($curl_instance, $curl_requests[$i]);
    }

    do {
        try {
            $curl_execute = curl_multi_exec($curl_instance, $curl_multi_exec_active);
        } catch (Exception $e) {
            error_log($e->getMessage());
        }
    } while ($curl_execute == CURLM_CALL_MULTI_PERFORM);


    /** Wait until data arrives on all sockets */
    $h = 0; // initialise a counter
    while ($curl_multi_exec_active && $curl_execute == CURLM_OK)
    {
        if (curl_multi_select($curl_instance) != -1)
        {
            do {
              $curl_data = curl_multi_exec($curl_instance, $curl_multi_exec_active);
              $curl_done = curl_multi_info_read($curl_instance);
              /** Check if there is data... */
              if ($curl_done['handle'] !== NULL)
              {
                  /** Continue ONLY if HTTP statuscode was OK (200) */
                  $info = curl_getinfo($curl_done['handle']);
                  if ($info['http_code'] == 200)
                  {
                      if (!empty(curl_multi_getcontent($curl_requests[$h]))) {
                          /** Curl request successful. Process data using the callback function. */
                          $callback(curl_multi_getcontent($curl_requests[$h]), $resources[$h][1]);
                      }
                      $h++; // count up
                   }
               }
            } while ($curl_data == CURLM_CALL_MULTI_PERFORM);
        }
    }

    /** Close all $curl_requests */
    foreach($curl_requests as $request) {
        curl_multi_remove_handle($curl_instance, $request);
    }
    curl_multi_close($curl_instance);

    return true;
}

/** Start fetching images from an Array */
cURLfetch($curl_httpresources);

非常感谢您的帮助,非常感谢!


我最终在经典循环中仅使用常规 cURL 请求来查询所有 >1'000 张图像并下载带有“HTTP 200 OK”响应的图像。我最初担心服务器可能会由于潜在的错误识别 DDoS 而切断连接,但没有效果,这就是为什么这种方法非常适合我的情况。

这是我使用的常规 cURL 请求的最终函数:

function cURLfetchUrl($url, $save_as_file)
{
    /** Validate $url & $save_as_file (not empty, null, or alike) */
    if ( empty($url) || is_numeric($url) ) return false;
    if ( empty($save_as_file) || is_numeric($save_as_file) ) return false;

    /** Disable PHP timelimit, because this could take a while... */
    set_time_limit(0);

    try {
        /**
         * Set cURL options to be passed to a single request
         */
        $curl_request_options = [
                                    CURLOPT_USERAGENT => 'PHP-Script/1.0 (+https://website.com/)',
                                    CURLOPT_TIMEOUT => 5,
                                    CURLOPT_FOLLOWLOCATION => true,
                                    CURLOPT_RETURNTRANSFER => true,
                                ];

        /** Initialize & execute cURL-Request */
        $curl_instance = curl_init($url);
        curl_setopt_array($curl_instance, $curl_request_options);
        $curl_data = curl_exec($curl_instance);
        $curl_done = curl_getinfo($curl_instance);

        /** cURL request successful */
        if ($curl_done['http_code'] == 200)
        {
            /** Open a new file handle, write the file & close the file handle */
            if (file_put_contents($save_as_file, $curl_data) !== false) {
                // logging if file_put_contents was OK
            } else {
                // logging if file_put_contents FAILED
            }
        }

        /** Close the $curl_instance */
        curl_close($curl_instance);

        return true;

    } catch (Exception $e) {
        error_log($e->getMessage());
        return false;
    }
}

并执行它:

$curl_httpresources = [
    [ 'http://www.gravatar.com/avatar/example?d=mm&r=x&s=427'
    ,'/srv/www/data/images/1_unsplash.jpg' ],
    [ 'http://www.gravatar.com/avatar/example?d=identicon&r=x&s=427'
    ,'/srv/www/data/images/2_unsplash.jpg' ],
    [ 'http://www.gravatar.com/avatar/example?d=monsterid&r=x&s=427'
    ,'/srv/www/data/images/3_unsplash.jpg' ],
    [ 'http://www.gravatar.com/avatar/example?d=wavatar&r=x&s=427'
    ,'/srv/www/data/images/4_unsplash.jpg' ],
    [ 'http://www.gravatar.com/avatar/example?d=retro&r=x&s=427'
    ,'/srv/www/data/images/5_unsplash.jpg' ],
    [ 'http://www.gravatar.com/avatar/example?d=mm&r=x&s=427'
    ,'/srv/www/data/images/6_unsplash.jpg' ],
    [ 'http://www.gravatar.com/avatar/example?d=identicon&r=x&s=427'
    ,'/srv/www/data/images/7_unsplash.jpg' ],
    [ 'http://www.gravatar.com/avatar/example?d=monsterid&r=x&s=427'
    ,'/srv/www/data/images/8_unsplash.jpg' ],
    [ 'http://www.gravatar.com/avatar/example?d=wavatar&r=x&s=427'
    ,'/srv/www/data/images/9_unsplash.jpg' ],
    [ 'http://www.gravatar.com/avatar/example?d=retro&r=x&s=427'
    ,'/srv/www/data/images/10_unsplash.jpg' ],
];

/** cURL all request from the $curl_httpresources Array */
if (count($curl_httpresources) > 0)
{
    foreach ($curl_httpresources as $resource)
    {
        cURLfetchUrl($resource[0], $resource[1]);
    }
}

不过,如果有人有一个想法,如何使用curl_multi正确检索文件数据流,那就太好了,因为我对最初问题的回答只是显示了一种不同的方法 - 而不是解决最初的方法。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

curl_multi_exec:下载的一些图像丢失了一些数据/流不完整 的相关文章

  • 简单的 PHP 条件帮助: if($Var1 = in list($List) and $Cond2) - 这可能吗?

    这是一个可能的功能吗 我需要检查一个变量是否存在于我需要检查的变量列表中 并且 cond2 是否为 true 例如 if row name 1 2 3 Cond2 doThis 它对我不起作用 我在复制粘贴中更改的只是我的列表和变量名称 i
  • 单词之间没有空格的语言(例如亚洲语言)中的断词?

    我想让 MySQL 全文搜索适用于日语和中文文本以及任何其他语言 问题在于这些语言以及可能其他语言通常在单词之间没有空格 当您必须键入与文本中相同的句子时 搜索没有用 我不能只在每个字符之间添加空格 因为英语也必须有效 我想用 PHP 或
  • PHP 会话不适用于游戏

    我正在尝试模仿一款名为 SKUNK 用骰子玩 的游戏来完成一项作业 我无法让会话正常工作 这是我第一次使用 PHP 我还被告知无需会议即可完成 这是我的代码
  • PHP MySQL 使用选项/选择 HTML 表单标签进行多重搜索查询

    我正在尝试使用两个搜索字段设置基本的 MySQL LIKE 搜索 我不想拥有它 所以它有多个可选搜索字段 例如if isset POST city isset POST name 我不知道如何用 HTML 来做到这一点
  • FPDI/FPDF:水印和打印多页

    我修改了这个堆栈问题 当用户尝试下载文件时在 pdf 文件上应用水印 https stackoverflow com questions 3983432 applying watermarks on pdf files when users
  • preg_match_all 查询仅显示有问题的外部组

    我无法弄清楚如何只显示 preg 查询的外部组级别 我会给你一个例子 preg match all start end input matches 这个输入start1 start2 2end 1end产生这个输出start1 start2
  • 为什么同一个curl命令在windows和linux下输出不同的东西?

    为什么同样的curl o file https www link com 命令输出不同的东西 例如 如果我运行命令curl o source txt https www youtube com playlist list PLIx6Fwnp
  • 使用 SSL 证书验证 Web 浏览器

    是否可以使用 ssl 证书对 Web 浏览器进行身份验证 假设我在应用程序中存储私钥 有什么方法可以从浏览器读取密钥并尝试基于该私钥进行身份验证 您可以使用 SSL TLS 客户端证书身份验证来对浏览器 用户进行身份验证 服务器必须请求客户
  • 在 PHP 中使用 phpseclib 时出现 RSA 问题

    我正在尝试在 phpseclib 中使用 RSA 实现 我认为在函数中执行一次代码并重新使用该函数会更容易 当我尝试向代码发送短信时 我收到一条错误消息 提示 解密错误 测试还让我意识到每次代码运行时密文都是不同的 所以我显然在那里做错了什
  • 跟踪用户何时点击浏览器上的后退按钮

    是否可以检测用户何时单击浏览器的后退按钮 我有一个 Ajax 应用程序 如果我可以检测到用户何时单击后退按钮 我可以显示适当的数据 任何使用 PHP JavaScript 的解决方案都是优选的 任何语言的解决方案都可以 只需要我可以翻译成
  • Doctrine EntityManager 清除嵌套实体中的方法

    我想用学说批量插入处理 http doctrine orm readthedocs org en latest reference batch processing html为了优化大量实体的插入 问题出在 Clear 方法上 它表示此方法
  • 标准化 UTF-8 到底是什么?

    The 重症监护室项目 http userguide icu project org transforms normalization 现在也有一个PHP库 http us php net manual en class normalize
  • 一次播种多行 laravel 5

    我目前正在尝试为我的用户表播种 如果我像这样尝试 2 行 就会失败 如果我只使用单个数组而不是 users 数组内的 2 个数组来创建一些假数据 那么效果很好 我做错了什么 正确的方法是什么 class UserTableSeeder ex
  • php,统计字符并删除超过140个字符的内容

    我需要一个 PHP 函数来计算短语的字符数 如果短语长度超过 140 个字符 则此函数应删除所有其他字符并在短语末尾添加三个点 例如我们有 message I am what I am and you are what you are et
  • 使用正则表达式提取两个短语之间的所有单词[重复]

    这个问题在这里已经有答案了 我正在尝试使用以下正则表达式提取两个短语之间的所有单词 b item W w W 0 2 1 one W w W 0 3 business b b item W w W 0 2 3 three W w W 0 3
  • 如何在 Laravel 中使用 PUT http 动词提交表单

    我知道这个问题可能已经提出 但我就是无法让它发挥作用 如果有人可以帮助我 我将非常感激 我安装了 colletive form 但答案也可以是 html 表单标签 现在列出我的表格 我的路线和我的例外情况 Form model array
  • ini_set 'session.gc_maxlifetime' 为 1 天

    If I do ini set session gc maxlifetime 86400 这是否意味着用户可以将浏览器留在同一页面 非活动状态 最多 1 天 而不必担心会话被垃圾收集并被注销 如果服务器配置不支持此功能会发生什么 它会给我一
  • 简单的 PHP 表单:电子邮件附件(代码 Golf)

    想象一下 一个用户想要在其网站上放置一个表单 该表单将允许网站访问者上传一个文件和一条简单的消息 该消息将立即通过电子邮件发送 即 该文件未存储在服务器上 或者如果该文件存储在服务器上 仅暂时 作为文件附件 并在邮件正文中添加注释 查看更多
  • 无法显示 Laravel 欢迎页面

    我的服务器位于 DigitalOcean 云上 我正在使用 Ubuntu 和 Apache Web 服务器 我的家用计算机运行的是 Windows 7 我使用 putty 作为终端 遵循所有指示https laracasts com ser
  • 为什么curl允许使用文件URL方案,但wget不允许

    这个问题指的是curl 7 21 4和GNU Wget 1 13 4 我不知道答案是否特定于版本 使用文件 URI 方案 http en wikipedia org wiki File URI scheme我可以使用获取本地文件curl a

随机推荐

  • 展平单子栈

    所以我的第一个严肃的 haskell 项目中到处都有这样的代码 f MonadTrans t gt ExceptT t StateT A B C f do mapExceptT lift do lift do lift do r lt re
  • C++ 中集合集合的高效集合交集

    我有一个收藏std set 我想以最快的方式找到这个集合中所有集合的交集 集合中的集合数量通常非常小 5 10 每个集合中的元素数量通常小于 1000 但偶尔会达到 10000 左右 但是我需要进行数十次这些交集数千次 尽可能快 我尝试对以
  • WPF 的免费字体和颜色选择器?

    我正在为 WPF 寻找一些好的字体选择器和颜色选择器组件 我试图找到一些标准解决方案 例如 Winforms 组件 但似乎没有 我想知道为什么 它不一定是完美的 代码项目中的一些东西就足够了 但我更喜欢好看且直观易用的组件 谢谢 Look
  • 响应式 SVG 图像蒙版

    我使用 SVG 作为图像蒙版 但我不知道如何在调整页面大小时使 SVG 改变其大小 当我更改窗口大小时 SVG 内的图像会调整大小 但 SVG 不会 关于如何解决这个问题有什么想法吗 这是 SVG 代码
  • 避免在 Swift 中使用连续的“if let”声明[重复]

    这个问题在这里已经有答案了 在斯威夫特我用过if let声明来检查我的对象是否不是nil if let obj optionalObj 但有时候 我不得不面对连续的if let声明 if let obj optionalObj if let
  • 支持多个Python模块版本(具有相同版本的Python)

    我环顾四周 但找不到我的问题的明确答案 我非常合理地需要支持同一 Python 模块的 N 个版本 如果它们存储在同一个包 目录中 则它们必须具有唯一的名称 如下例所示 some package my module 1 0 py some
  • 通过 JavaScript 正则表达式获取 url 路径名的一部分

    我有以下网址 https www example com article f 1 test article 我需要通过 JavaScript 纯 JavaScript 从 url 中获取 1 部分 我知道我可以用 location path
  • knockoutjs 中的滑动动作绑定

    我在我的应用程序中使用淘汰赛作为主要框架 它必须支持平板电脑和移动设备 由于框架是基于绑定处理程序构建的 我想知道如何实现对操作 如滑动和其他特定于设备的操作 的自定义绑定 或者也许有类似的事情完成 可能为时已晚 但这里有一个库 将触摸绑定
  • DB2 WITH 语句可以用作 UPDATE 或 MERGE 的一部分吗?

    我需要更新数据库表中的一些行 如何识别要更新的行涉及一系列复杂的语句 我设法将它们归结为一系列WITH语句 现在我有了正确的数据值 我需要更新表 由于我设法使用WITH语句获取这些值 因此我希望在更新 合并中使用它 一个简化的示例如下 wi
  • 如何更改 Ubuntu 中的文件权限 [重复]

    这个问题在这里已经有答案了 在 Ubuntu 中 我想更改整个文件夹及其所有子文件夹的文件权限以供任何人读 写 我努力了sudo chmod 666 var www and sudo chmod 755 var www没有成功 update
  • Facebook 重置“在 Facebook 上分享”链接的缓存

    我刚刚更新了我们网站的的开放图协议 我刚刚注意到 每当我分享一些链接时 旧的是 Facebook 正在解析的 但是 对于我运行的那些链接debugger https developers facebook com tools debug他们
  • 仅当 command1 在 cmd windows shell 中成功时才运行 command2

    我们如何组合 cmd shell 语言中的命令 以便仅在第一个命令成功完成时才执行第二个命令 类似以下 bash 命令 make a out a out仅在以下情况下执行make那是成功的 下列 command1 command2 应该致力
  • 读取 nul 分隔字段

    给定这个文件 printf alpha 0bravo 0charlie gt delta txt 我想将这些字段读入单独的变量中 我使用的原因 空分隔符是因为字段将包含文件路径 其中可以包含 除 null 之外的任何字符 我尝试了这些命令
  • Android 中某些相机分辨率下的不同捕获输出大小

    我正在使用 Android Camera2 API 开发一个自定义相机应用程序 您可以在手机中可用的不同相机和视频分辨率之间切换 它还提供了拍摄 1 1 方形照片的可能性 为了拍摄方形照片 我拍摄了一张正常的 4 3 照片 然后将其裁剪以保
  • GetType 返回 Int 而不是 System.Int32

    GetType ToString 返回对象的全名 我想要您通常用来实例化该对象的名称 即 int 而不是 Int32 有没有办法做到这一点 C 有许多 类型 它们实际上是 NET CLR 的关键字别名Types 在这种情况下 int是 C
  • 如果不允许任务之间共享可变状态,为什么 Rust 具有互斥体和其他同步原语?

    我的理解是 Rust 中的任务之间不可能共享可变状态 那么为什么 Rust 有这样的东西mutexes https doc rust lang org std sync struct Mutex html在语言中 他们的目的是什么 不允许在
  • 如何在asp.net core中更改Razor中的根路径〜/

    我有一个带有 Razor 的 ASP NET Core 2 1 MVC 应用程序 它广泛使用 path syntax 如果应用程序从域根运行 例如 从http localhost 5000 但是当我在非根位置运行应用程序时 例如 http
  • 错误:您需要包含一些实现 __karma__.start 方法的适配器

    我正在尝试向我的项目之一添加一些单元测试 到目前为止 我已经安装并配置了 karma 并安装了 jasmine 我的里面有一个测试文件test folder karma 服务器已启动 浏览器页面已准备就绪 但是karma run失败如下 k
  • 如何翻译$url_handlers?

    我遇到一个情况 需要翻译以下内容 url handlers对于不同的国家 因此 在英文网站上 URL 如下所示 http website com gyms boston group training http website com gym
  • curl_multi_exec:下载的一些图像丢失了一些数据/流不完整

    我已经实现了一个 PHP 函数 它检查并下载大量图像 gt 1 000 使用数组传递给它 使用 PHPcurl multi init method 经过几次返工后 因为我得到了 0 字节文件等内容 我现在有一个下载所有图像的解决方案 但下载