php 我可以让curl_init()工作,但curl_multi_init()不行

tcbh2hod  于 2023-02-21  发布在  PHP
关注(0)|答案(1)|浏览(202)
    • bounty将在6天后过期**。回答此问题可获得+50声望奖励。Jonathon Philip Chambers希望引起更多人对此问题的关注:即使是一个线索或洞察力,导致我发现正确的答案对我自己是值得的绿色勾选。

这是我第一次使用curl_multi_init(),所以我可能误解了一些东西。学习正确使用它对我来说比解决我的问题更重要,因为这个特殊的函数将解决我未来的许多问题。
这个特殊的调用是为了上传Etsy的照片。Etsy文档在这里。
它在Postman中运行良好。postman为"PHP-cURL"生成的代码片段运行良好。即使在我编辑它之后,它仍然运行良好。
问题是,我有超过1000张高分辨率的图片要上传,所以从头到尾运行整个代码片段,然后循环1000次,无论我的php.ini设置有多慷慨,都会超时。
所以,我一行一行地将现有代码与同步代码段合并,我一定是做错了什么。这个例子几乎完全是实时代码。我只是删除/简化了不相关的内容和个人信息。(希望我没有删除/简化bug。):

<?php
include_once 'databaseStuff.php';
include_once 'EtsyTokenStuff.php';
$result = mysqli_query($conn, "SELECT product, listing_id, alt_text, dataStuff;");
$multiCurl = [];
$multiResult = [];
$multiHandle = curl_multi_init();
if (mysqli_num_rows($result) > 0){
    while ($row = mysqli_fetch_assoc($result)){
        for($image = 1; $image <=2; $image++){
            $multiCurl[$row['product'] . "_" . $image] = curl_init();
            curl_setopt_array($multiCurl[$row['product'] . "_" . $image], 
                array(
                    CURLOPT_URL => "https://openapi.etsy.com/v3/application/shops/$myShopNumber/listings/" . $row['listing_id'] . "/images",
                    CURLOPT_RETURNTRANSFER => true,
                    CURLOPT_ENCODING => '',
                    CURLOPT_MAXREDIRS => 10,
                    CURLOPT_TIMEOUT => 0,
                    CURLOPT_FOLLOWLOCATION => true,
                    CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
                    CURLOPT_CUSTOMREQUEST => 'POST',
                    CURLOPT_POSTFIELDS => array(
                        "image" => new CURLFILE(
                            [
                                1 => "img/imagePathStuff/" . $row['product'] . ".jpg",
                                2 => "img/differentImagePathStuff/" . $row['product'] . ".jpg"
                            ][$image]
                        ),
                        // "listing_image_id" =>,
                        "rank" => $image,
                        "overwrite" => true,
                        // "is_watermarked" =>,
                        "alt_text" => $row['alt_text']
                    ),
                    CURLOPT_HTTPHEADER => array(
                        "x-api-key: $myAPIKey",
                        "authorization: Bearer {$etsyAccessToken}"
                    ),
                )
            );
            curl_multi_add_handle($multiHandle, $multiCurl[$row['product'] . "_" . $image]);
        }
    }
    $index = null;
    do {
        curl_multi_exec($multiHandle, $index);
    } while($index > 0);
    foreach($multiCurl as $k => $curlHandle){
        $multiResult[$k] = curl_multi_getcontent($curlHandle);
        curl_multi_remove_handle($multiHandle, $curlHandle);
    }
    curl_multi_close($multiHandle);
}

一旦它开始工作,我可能会把它分成函数块,但我更喜欢以这种格式编辑损坏的代码,并在以后添加函数调用。
由于以前从未使用过这些函数,我不确定它们应该如何工作,但我注意到的行为是:

  • 所有代码执行,从头到尾,没有致命错误。
  • do-while循环执行一次,然后再循环一次(也许它应该这样做,也许它应该为每张照片循环一次,但在任何地方都无法澄清这一点)。
  • 它应该更新照片,不幸的是,第一次测试是在非常小的编辑,但再次尝试包括一个故意错误的照片,我至少知道,该特定的照片没有更新,所以可能没有更新。
  • curl_multi_getcontent($curlHandle)始终返回空字符串
  • curl_multi_exec($multiHandle, $index)总是返回0(之前声称它是1002是不正确的。1002实际上是运行函数后第二个参数$index的值。)
  • 这个调用通常会对201有非常详细的响应,并且至少会返回400、401、403、404、409和500的错误,但是我认为我的代码甚至还没有深入到进行调用的程度,我甚至还没有弄清楚如何获得响应代码。
  • 对于一个从我的服务器向Etsy的服务器传输超过1000张高分辨率图像的脚本来说,它的执行速度当然非常快。
  • $multiHandle似乎按预期工作。至少,var_dump($multiHandle)显示了其中所有正确的文件名。

我已经因为这个问题损失了整整一天的工作时间,但是如果是一个小的打字错误造成的,我也不会感到惊讶。

y1aodyip

y1aodyip1#

这只是一种猜测,但是如果您的问题是超时,那么您编写的以下循环可能就是问题所在:

$index = null;
    do {
        curl_multi_exec($multiHandle, $index);
    } while($index > 0);

您正在重复调用curl_multi_exec,这会在您等待所有上传完成的同时消耗CPU。您应该只定期检查上传状态,并在其间进入等待状态。这应该会减少您的总CPU时间:

while (TRUE) {
        $status = curl_multi_exec($multiHandle, $activeCount);
        if ($status == CURLM_OK && $activeCount) {
            // Wait some time before checking again:
            curl_multi_select($mh, $timeout=1.0);
        }
        else {
            break;
        }
    }

相关问题