Làm cách nào để tạo một yêu cầu GET không đồng bộ trong PHP?


97

Tôi muốn thực hiện một yêu cầu GET đơn giản tới một tập lệnh khác trên một máy chủ khác. Làm thế nào để tôi làm điều này?

Trong một trường hợp, tôi chỉ cần yêu cầu một tập lệnh bên ngoài mà không cần bất kỳ đầu ra nào.

make_request('http://www.externalsite.com/script1.php?variable=45'); //example usage

Trong trường hợp thứ hai, tôi cần lấy đầu ra văn bản.

$output = make_request('http://www.externalsite.com/script2.php?variable=45');
echo $output; //string output

Thành thật mà nói, tôi không muốn làm lung tung với CURL vì đây không thực sự là công việc của CURL. Tôi cũng không muốn sử dụng http_get vì tôi không có tiện ích mở rộng PECL.

Fsockopen sẽ hoạt động? Nếu vậy, làm cách nào để thực hiện việc này mà không cần đọc nội dung của tệp? Có không có cách nào khác?

Cảm ơn tất cả

Cập nhật

Tôi nên nói thêm, trong trường hợp đầu tiên, tôi không muốn đợi kịch bản trả về bất cứ điều gì. Theo tôi hiểu thì file_get_contents () sẽ đợi trang tải đầy đủ, v.v.?


6
@William: Vâng, hầu hết các câu hỏi có thể được coi là bản sao chính xác của chính chúng. 8-) Tôi nghĩ rằng bạn được đăng vào liên kết sai ...
RichieHindle


1
Tôi có ý định đăng liên kết mà musicfreak đã đăng, trộn lẫn các tab của tôi ;-)
William Brendel

2
@Richie: Hầu hết các câu hỏi? ;)
Sasha Chedygov

1
Tôi đã đặt lại câu hỏi để phân biệt nó với câu hỏi khác, vì có vẻ như bạn muốn đưa ra một yêu cầu không quan tâm đến việc sử dụng phản hồi (vì vậy nó có thể xảy ra khi phần còn lại của tập lệnh chạy). Hoàn nguyên nếu tôi nhầm!
dbr

Câu trả lời:


52

file_get_contents sẽ làm những gì bạn muốn

$output = file_get_contents('http://www.example.com/');
echo $output;

Chỉnh sửa: Một cách để loại bỏ yêu cầu GET và quay lại ngay lập tức.

Trích dẫn từ http://petewarden.typepad.com/searchbrowser/2008/06/how-to-post-an.html

function curl_post_async($url, $params)
{
    foreach ($params as $key => &$val) {
      if (is_array($val)) $val = implode(',', $val);
        $post_params[] = $key.'='.urlencode($val);
    }
    $post_string = implode('&', $post_params);

    $parts=parse_url($url);

    $fp = fsockopen($parts['host'],
        isset($parts['port'])?$parts['port']:80,
        $errno, $errstr, 30);

    $out = "POST ".$parts['path']." HTTP/1.1\r\n";
    $out.= "Host: ".$parts['host']."\r\n";
    $out.= "Content-Type: application/x-www-form-urlencoded\r\n";
    $out.= "Content-Length: ".strlen($post_string)."\r\n";
    $out.= "Connection: Close\r\n\r\n";
    if (isset($post_string)) $out.= $post_string;

    fwrite($fp, $out);
    fclose($fp);
}

Điều này làm là mở một ổ cắm, kích hoạt một yêu cầu nhận và ngay lập tức đóng ổ cắm và quay trở lại.


6
curl_post_async gửi yêu cầu POST, không phải GET.
Vinko Vrsalovic

13
Tôi có đúng khi nói rằng chức năng này được đặt tên không đúng? Nó thực sự không liên quan gì đến thư viện curl. Đó là fsock_post_async () giống như nó
MikeMurko

61
Đây KHÔNG phải là không đồng bộ! Đặc biệt nếu máy chủ ở phía bên kia không hoạt động, đoạn mã này sẽ bị treo trong 30 giây (tham số thứ 5 trong fsockopen). Ngoài ra, fwrite sẽ dành thời gian ngọt ngào để thực thi (bạn có thể giới hạn với stream_set_timeout ($ fp, $ my_timeout). Cách tốt nhất bạn có thể làm là đặt thời gian chờ thấp trên fsockopen thành 0,1 (100ms) và $ my_timeout thành 100ms . Bạn có nguy cơ mặc dù, rằng thời gian chờ theo yêu cầu.
Chris Cinelli

4
Điều này không liên quan gì đến async. Đây là đồng bộ hóa khi nó được ... Không đồng bộ có nghĩa là thực hiện các tác vụ khác trong khi tác vụ này đang được hoàn thành. Đó là thực hiện song song.
CodeAngry

17
Đây không phải là async cũng không phải là nó sử dụng curl, làm thế nào bạn dám gọi nó curl_post_asyncvà nhận được upvotes thậm chí ...
Daniel W.

33

Đây là cách làm cho câu trả lời của Marquis hoạt động với cả yêu cầu POST và GET:

  // $type must equal 'GET' or 'POST'
  function curl_request_async($url, $params, $type='POST')
  {
      foreach ($params as $key => &$val) {
        if (is_array($val)) $val = implode(',', $val);
        $post_params[] = $key.'='.urlencode($val);
      }
      $post_string = implode('&', $post_params);

      $parts=parse_url($url);

      $fp = fsockopen($parts['host'],
          isset($parts['port'])?$parts['port']:80,
          $errno, $errstr, 30);

      // Data goes in the path for a GET request
      if('GET' == $type) $parts['path'] .= '?'.$post_string;

      $out = "$type ".$parts['path']." HTTP/1.1\r\n";
      $out.= "Host: ".$parts['host']."\r\n";
      $out.= "Content-Type: application/x-www-form-urlencoded\r\n";
      $out.= "Content-Length: ".strlen($post_string)."\r\n";
      $out.= "Connection: Close\r\n\r\n";
      // Data goes in the request body for a POST request
      if ('POST' == $type && isset($post_string)) $out.= $post_string;

      fwrite($fp, $out);
      fclose($fp);
  }

2
Đây là một đoạn mã hữu ích và tôi đã sử dụng nó ở đây và ở đó, nhưng bây giờ tôi thấy rằng tôi cần phải làm điều tương tự, nhưng với một trang web SSL. Có điều gì tôi cần thay đổi ngoài kiểu HTTP / 1.1 và cổng không?
Kevin Jhangiani

2
Trong Câu trả lời cho câu hỏi về việc sử dụng điều này cho SSL, bạn có thể đặt nó thành SSL bằng cách thay đổi cổng thành 443 và thêm ssl: // vào tên cổng trong fsockopen: $ fp = fsockopen ("ssl: //". $ Part ['host '],
Michael Dogger

1
"Có gì tôi cần thay đổi ngoài kiểu HTTP / 1.1 và cổng không?" - Có, bạn nên gọi fsockopen () với tên máy chủ ssl://hostnamethay vì chỉ hostname.
Cowlby

22
Đây KHÔNG phải là không đồng bộ! Đặc biệt nếu máy chủ ở phía bên kia không hoạt động, đoạn mã này sẽ bị treo trong 30 giây (tham số thứ 5 trong fsockopen). Ngoài ra, fwrite sẽ dành thời gian ngọt ngào để thực thi (bạn có thể giới hạn với stream_set_timeout ($ fp, $ my_timeout). Cách tốt nhất bạn có thể làm là đặt thời gian chờ thấp trên fsockopen thành 0,1 (100ms) và $ my_timeout thành 100ms . Bạn có nguy cơ mặc dù, rằng thời gian chờ theo yêu cầu.
Chris Cinelli

1
Nội dung-Độ dài không được đặt cho GET. Có thể trong một số trường hợp không gây ra lỗi nhưng trong trường hợp của tôi dẫn đến yêu cầu không được xử lý bởi tập lệnh php được gọi là.
user3285954

13

Liên quan đến cập nhật của bạn, về việc không muốn đợi toàn bộ trang tải - tôi nghĩ rằng một HTTP HEAD yêu cầu là những gì bạn đang tìm kiếm ..

get_headers nên làm điều này - tôi nghĩ rằng nó chỉ yêu cầu các tiêu đề, vì vậy sẽ không được gửi toàn bộ nội dung trang.

"PHP / Curl: HEAD Request mất nhiều thời gian trên một số trang web" mô tả cách thực hiệnHEAD yêu cầu bằng PHP / Curl

Nếu bạn muốn kích hoạt yêu cầu và hoàn toàn không giữ tập lệnh, có một số cách, phức tạp khác nhau ..

  • Thực thi yêu cầu HTTP như một quy trình nền, php thực thi một quy trình nền - về cơ bản bạn sẽ thực thi một cái gì đó như thế "wget -O /dev/null $carefully_escaped_url"- đây sẽ là nền tảng cụ thể và bạn phải thực sự cẩn thận về việc thoát các tham số vào lệnh
  • Thực thi một tập lệnh PHP trong nền - về cơ bản giống như phương thức xử lý UNIX, nhưng thực thi một tập lệnh PHP chứ không phải là một lệnh shell
  • Có một "hàng đợi công việc", sử dụng cơ sở dữ liệu (hoặc một cái gì đó như cây đậu có khả năng quá mức cần thiết). Bạn thêm một URL vào hàng đợi và một quy trình nền hoặc cron-job thường xuyên kiểm tra các công việc mới và thực hiện các yêu cầu trên URL

1 cho các tùy chọn thú vị khác nhau mà tôi đã không nghĩ đến trước đây
Jasdeep Khalsa

"Tôi nghĩ rằng nó chỉ yêu cầu các tiêu đề" - Có lẽ, nhưng không có gì để ngăn một tài liệu gửi một cơ quan phản hồi đầy đủ để phản hồi yêu cầu HEAD. Và tôi giả sử phương pháp này sẽ sử dụng fsock dưới mui xe và buộc nó phải đợi (và đọc) phản hồi đầy đủ.
hiburn8

6

Bạn không. Mặc dù PHP cung cấp rất nhiều cách để gọi một URL, nhưng nó không cung cấp hỗ trợ xuất sắc để thực hiện bất kỳ loại xử lý không đồng bộ / phân luồng nào cho mỗi yêu cầu / chu kỳ thực thi. Bất kỳ phương pháp gửi yêu cầu URL nào (hoặc câu lệnh SQL, hoặc v.v.) đều sẽ đợi một số loại phản hồi. Bạn sẽ cần một số loại hệ thống phụ chạy trên máy cục bộ để đạt được điều này (google xung quanh cho "hàng đợi công việc php")


1
Có một vụ hack ở đây: stackoverflow.com/questions/124462/asynchronous-php-calls (câu trả lời của Christian Davén) nhưng tôi đồng ý rằng xếp hàng sẽ là cách thích hợp để thực hiện.
Chris Cinelli

Tôi nghĩ câu trả lời này từ năm 2009 giờ đã lỗi thời. Các thư viện tật ham ăn PHP bây giờ đã hỗ trợ để thực hiện yêu cầu đồng thời và không đồng bộ.
Simon East

6

Tôi muốn giới thiệu cho bạn thư viện PHP đã được thử nghiệm tốt: curl-easy

<?php
$request = new cURL\Request('http://www.externalsite.com/script2.php?variable=45');
$request->getOptions()
    ->set(CURLOPT_TIMEOUT, 5)
    ->set(CURLOPT_RETURNTRANSFER, true);

// add callback when the request will be completed
$request->addListener('complete', function (cURL\Event $event) {
    $response = $event->response;
    $content = $response->getContent();
    echo $content;
});

while ($request->socketPerform()) {
    // do anything else when the request is processed
}

Các thư viện tật ham ăn PHP cũng đã hỗ trợ để thực hiện yêu cầu đồng thời và không đồng bộ.
Simon East

Guzzle tuyên bố rằng nó có hỗ trợ, nhưng thử nghiệm phương thức postAsync của nó có vẻ như nó thực hiện đồng bộ 150 ms và sau đó là 2 ms không đồng bộ. Tôi đã dành hơn một giờ để cố gắng sửa chữa nó mà không thành công - tôi không khuyên bạn nên làm như vậy.
Velizar Hristov

4

Nếu bạn đang sử dụng môi trường Linux thì bạn có thể sử dụng lệnh execute của PHP để gọi curl linux. Đây là mã mẫu, sẽ tạo một bài đăng HTTP không đồng bộ.

function _async_http_post($url, $json_string) {
  $run = "curl -X POST -H 'Content-Type: application/json'";
  $run.= " -d '" .$json_string. "' " . "'" . $url . "'";
  $run.= " > /dev/null 2>&1 &";
  exec($run, $output, $exit);
  return $exit == 0;
}

Mã này không cần thêm bất kỳ ngôn ngữ PHP nào và nó có thể hoàn thành bài đăng http trong vòng chưa đầy 10 mili giây.


1
đây là một ý tưởng rất tồi: người thực thi thất bại rất nhiều: hãy tưởng tượng rằng 6/200 khách hàng sẽ không nhận được email xác nhận của họ cho một đặt phòng đã thanh toán ...
HellBaby

Điều này phù hợp với tôi, vì tôi chỉ cần ping để bắt đầu một tập lệnh khác trên máy chủ khác. Tôi vừa mới sử dụng nó như thế: _async_http_post ($ url, ''); Và điều này đang hoạt động trên các máy chủ hỗ trợ OVH ... Điều đó thật tuyệt.
Kilowog

4
function make_request($url, $waitResult=true){
    $cmi = curl_multi_init();

    $curl = curl_init();
    curl_setopt($curl, CURLOPT_URL, $url);
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);

    curl_multi_add_handle($cmi, $curl);

    $running = null;
    do {
        curl_multi_exec($cmi, $running);
        sleep(.1);
        if(!$waitResult)
        break;
    } while ($running > 0);
    curl_multi_remove_handle($cmi, $curl);
    if($waitResult){
        $curlInfos = curl_getinfo($curl);
        if((int) $curlInfos['http_code'] == 200){
            curl_multi_close($cmi);
            return curl_multi_getcontent($curl);
        }
    }
    curl_multi_close($cmi);
}

Bạn có thể làm cho nó trả về một đối tượng cho phép bạn gọi getstatus()hoặc waitSend()hoặc waitResult(). Bằng cách đó, người gọi có thể nhận được hành vi không đồng bộ hoàn toàn bằng cách gọi trong một vòng lặp để kiểm tra xem có kết quả hay không và nếu không, hãy tiếp tục bất kỳ tác vụ nào khác đang chạy. Hmm, bây giờ tôi muốn cổng Tasktừ Net để php ...
binki

3

Vấn đề thú vị. Tôi đoán bạn chỉ muốn kích hoạt một số quy trình hoặc hành động trên máy chủ khác, nhưng không quan tâm đến kết quả và muốn tập lệnh của bạn tiếp tục. Có thể có điều gì đó trong cURL có thể làm cho điều này xảy ra, nhưng bạn có thể muốn xem xét sử dụng exec()để chạy một tập lệnh khác trên máy chủ thực hiện lệnh gọi nếu cURL không thể thực hiện được. (Thông thường mọi người muốn kết quả của lệnh gọi tập lệnh, vì vậy tôi không chắc liệu PHP có khả năng chỉ kích hoạt quá trình hay không.) Với exec()bạn có thể chạy một wgethoặc thậm chí một tập lệnh PHP khác thực hiện yêu cầu với file_get_conents().


2

Tốt hơn bạn nên cân nhắc sử dụng Hàng đợi Tin nhắn thay vì các phương pháp được khuyến nghị. Tôi chắc rằng đây sẽ là giải pháp tốt hơn, mặc dù nó đòi hỏi nhiều công việc hơn một chút so với việc chỉ gửi một yêu cầu.


2

để tôi chỉ cho bạn cách của tôi :)

cần cài đặt nodejs trên máy chủ

(máy chủ của tôi gửi 1000 https yêu cầu nhận chỉ mất 2 giây)

url.php:

<?
$urls = array_fill(0, 100, 'http://google.com/blank.html');

function execinbackground($cmd) { 
    if (substr(php_uname(), 0, 7) == "Windows"){ 
        pclose(popen("start /B ". $cmd, "r"));  
    } 
    else { 
        exec($cmd . " > /dev/null &");   
    } 
} 
fwite(fopen("urls.txt","w"),implode("\n",$urls);
execinbackground("nodejs urlscript.js urls.txt");
// { do your work while get requests being executed.. }
?>

urlscript.js>

var https = require('https');
var url = require('url');
var http = require('http');
var fs = require('fs');
var dosya = process.argv[2];
var logdosya = 'log.txt';
var count=0;
http.globalAgent.maxSockets = 300;
https.globalAgent.maxSockets = 300;

setTimeout(timeout,100000); // maximum execution time (in ms)

function trim(string) {
    return string.replace(/^\s*|\s*$/g, '')
}

fs.readFile(process.argv[2], 'utf8', function (err, data) {
    if (err) {
        throw err;
    }
    parcala(data);
});

function parcala(data) {
    var data = data.split("\n");
    count=''+data.length+'-'+data[1];
    data.forEach(function (d) {
        req(trim(d));
    });
    /*
    fs.unlink(dosya, function d() {
        console.log('<%s> file deleted', dosya);
    });
    */
}


function req(link) {
    var linkinfo = url.parse(link);
    if (linkinfo.protocol == 'https:') {
        var options = {
        host: linkinfo.host,
        port: 443,
        path: linkinfo.path,
        method: 'GET'
    };
https.get(options, function(res) {res.on('data', function(d) {});}).on('error', function(e) {console.error(e);});
    } else {
    var options = {
        host: linkinfo.host,
        port: 80,
        path: linkinfo.path,
        method: 'GET'
    };        
http.get(options, function(res) {res.on('data', function(d) {});}).on('error', function(e) {console.error(e);});
    }
}


process.on('exit', onExit);

function onExit() {
    log();
}

function timeout()
{
console.log("i am too far gone");process.exit();
}

function log() 
{
    var fd = fs.openSync(logdosya, 'a+');
    fs.writeSync(fd, dosya + '-'+count+'\n');
    fs.closeSync(fd);
}

1
Đây không phải là một giải pháp PHP thuần túy.
binki

2

Đối với tôi, câu hỏi về yêu cầu GET không đồng bộ xuất hiện vì tôi đã gặp phải tình huống khi tôi cần thực hiện hàng trăm yêu cầu , nhận và xử lý dữ liệu kết quả cho mọi yêu cầu và mọi yêu cầu đều mất một phần nghìn giây đáng kể để thực hiện dẫn đến vài phút (!) tổng thực thi với đơn giản file_get_contents.

Trong trường hợp này, đó là nhận xét rất hữu ích của w_haigh tại php.net về function http://php.net/manual/en/ Chức năng.curl-multi-init.php

Vì vậy, đây là phiên bản nâng cấp và làm sạch của tôi để thực hiện đồng thời nhiều yêu cầu. Đối với trường hợp của tôi, nó tương đương với cách "không đồng bộ". Có thể nó sẽ giúp ích cho ai đó!

// Build the multi-curl handle, adding both $ch
$mh = curl_multi_init();

// Build the individual requests, but do not execute them
$chs = [];
$chs['ID0001'] = curl_init('http://webservice.example.com/?method=say&word=Hello');
$chs['ID0002'] = curl_init('http://webservice.example.com/?method=say&word=World');
// $chs[] = ...
foreach ($chs as $ch) {
    curl_setopt_array($ch, [
        CURLOPT_RETURNTRANSFER => true,  // Return requested content as string
        CURLOPT_HEADER => false,         // Don't save returned headers to result
        CURLOPT_CONNECTTIMEOUT => 10,    // Max seconds wait for connect
        CURLOPT_TIMEOUT => 20,           // Max seconds on all of request
        CURLOPT_USERAGENT => 'Robot YetAnotherRobo 1.0',
    ]);

    // Well, with a little more of code you can use POST queries too
    // Also, useful options above can be  CURLOPT_SSL_VERIFYHOST => 0  
    // and  CURLOPT_SSL_VERIFYPEER => false ...

    // Add every $ch to the multi-curl handle
    curl_multi_add_handle($mh, $ch);
}

// Execute all of queries simultaneously, and continue when ALL OF THEM are complete
$running = null;
do {
    curl_multi_exec($mh, $running);
} while ($running);

// Close the handles
foreach ($chs as $ch) {
    curl_multi_remove_handle($mh, $ch);
}
curl_multi_close($mh);

// All of our requests are done, we can now access the results
// With a help of ids we can understand what response was given
// on every concrete our request
$responses = [];
foreach ($chs as $id => $ch) {
    $responses[$id] = curl_multi_getcontent($ch);
    curl_close($ch);
}
unset($chs); // Finita, no more need any curls :-)

print_r($responses); // output results

Thật dễ dàng để viết lại điều này để xử lý POST hoặc các loại yêu cầu HTTP (S) khác hoặc bất kỳ kết hợp nào của chúng. Và hỗ trợ Cookie, chuyển hướng, http-auth, v.v.


Ồ .. Tôi thấy câu hỏi được tạo vào năm 2009 và tôi viết câu trả lời của mình vào năm 2016 :) Nhưng rất nhiều người trong chúng ta google php nhận được không đồng bộ và đến đây.
FlameStorm

Có, tôi cũng đã đến đây khi Googling. Một số lập trình viên cũng có thể muốn xem thư viện Guzzle PHP có hỗ trợ thực hiện các yêu cầu đồng thời và không đồng bộ.
Simon East

1

Thử:

//Your Code here
$pid = pcntl_fork();
if ($pid == -1) {
     die('could not fork');
}
else if ($pid)
{
echo("Bye")  
}
else
{
     //Do Post Processing
}

Điều này sẽ KHÔNG hoạt động như một mô-đun apache, bạn cần phải sử dụng CGI.


1

Tôi đã tìm thấy liên kết thú vị này để thực hiện xử lý không đồng bộ (nhận yêu cầu).

askapache

Hơn nữa, bạn có thể thực hiện xử lý không đồng bộ bằng cách sử dụng hàng đợi thông báo như beantalkd chẳng hạn.


1

Đây là sự điều chỉnh của câu trả lời được chấp nhận để thực hiện một yêu cầu GET đơn giản.

Một điều cần lưu ý nếu máy chủ thực hiện bất kỳ ghi lại url nào, điều này sẽ không hoạt động. Bạn sẽ cần sử dụng một ứng dụng khách http đầy đủ tính năng hơn.

  /**
   * Performs an async get request (doesn't wait for response)
   * Note: One limitation of this approach is it will not work if server does any URL rewriting
   */
  function async_get($url)
  {
      $parts=parse_url($url);

      $fp = fsockopen($parts['host'],
          isset($parts['port'])?$parts['port']:80,
          $errno, $errstr, 30);

      $out = "GET ".$parts['path']." HTTP/1.1\r\n";
      $out.= "Host: ".$parts['host']."\r\n";
      $out.= "Connection: Close\r\n\r\n";
      fwrite($fp, $out);
      fclose($fp);
  }

1

Chỉ là một số chỉnh sửa về kịch bản được đăng ở trên. Sau đây là làm việc cho tôi

function curl_request_async($url, $params, $type='GET')
    {
        $post_params = array();
        foreach ($params as $key => &$val) {
            if (is_array($val)) $val = implode(',', $val);
            $post_params[] = $key.'='.urlencode($val);
        }
        $post_string = implode('&', $post_params);

        $parts=parse_url($url);
        echo print_r($parts, TRUE);
        $fp = fsockopen($parts['host'],
            (isset($parts['scheme']) && $parts['scheme'] == 'https')? 443 : 80,
            $errno, $errstr, 30);

        $out = "$type ".$parts['path'] . (isset($parts['query']) ? '?'.$parts['query'] : '') ." HTTP/1.1\r\n";
        $out.= "Host: ".$parts['host']."\r\n";
        $out.= "Content-Type: application/x-www-form-urlencoded\r\n";
        $out.= "Content-Length: ".strlen($post_string)."\r\n";
        $out.= "Connection: Close\r\n\r\n";
        // Data goes in the request body for a POST request
        if ('POST' == $type && isset($post_string)) $out.= $post_string;
        fwrite($fp, $out);
        fclose($fp);
    }

Tôi đang gặp sự cố, trong đó fwrite trả về một số byte dương, nhưng điểm cuối tập lệnh không được gọi (không ghi nhật ký) .. nó chỉ hoạt động khi tôi sử dụng: while (! Feof ($ fp)) {fgets ($ fp , 128); }
Miguel

1

Dường như không ai đề cập đến Guzzle , là một ứng dụng khách PHP HTTP giúp dễ dàng gửi các yêu cầu HTTP. Nó có thể hoạt động có hoặc không Curl. Nó có thể gửi cả yêu cầu đồng bộ và không đồng bộ.

$client = new GuzzleHttp\Client();
$promise = $client->requestAsync('GET', 'http://httpbin.org/get');
$promise->then(
    function (ResponseInterface $res) {
        echo $res->getStatusCode() . "\n";
    },
    function (RequestException $e) {
        echo $e->getMessage() . "\n";
        echo $e->getRequest()->getMethod();
    }
);

Có, nhiều câu trả lời trong chủ đề này khá cũ, nhưng Guzzle chắc chắn là lựa chọn tốt nhất mà tôi đã xem qua vào năm 2018, cảm ơn bạn đã đăng bài.
Simon East

0

Dựa trên chủ đề này, tôi đã thực hiện điều này cho dự án codeigniter của mình. Nó hoạt động tốt. Bạn có thể có bất kỳ chức năng nào được xử lý trong nền.

Một bộ điều khiển chấp nhận các cuộc gọi không đồng bộ.

class Daemon extends CI_Controller
{
    // Remember to disable CI's csrf-checks for this controller

    function index( )
    {
        ignore_user_abort( 1 );
        try
        {
            if ( strcmp( $_SERVER['REMOTE_ADDR'], $_SERVER['SERVER_ADDR'] ) != 0 && !in_array( $_SERVER['REMOTE_ADDR'], $this->config->item( 'proxy_ips' ) ) )
            {
                log_message( "error", "Daemon called from untrusted IP-address: " . $_SERVER['REMOTE_ADDR'] );
                show_404( '/daemon' );
                return;
            }

            $this->load->library( 'encrypt' );
            $params = unserialize( urldecode( $this->encrypt->decode( $_POST['data'] ) ) );
            unset( $_POST );
            $model = array_shift( $params );
            $method = array_shift( $params );
            $this->load->model( $model );
            if ( call_user_func_array( array( $this->$model, $method ), $params ) === FALSE )
            {
                log_message( "error", "Daemon could not call: " . $model . "::" . $method . "()" );
            }
        }
        catch(Exception $e)
        {
            log_message( "error", "Daemon has error: " . $e->getMessage( ) . $e->getFile( ) . $e->getLine( ) );
        }
    }
}

Và một thư viện thực hiện các lệnh gọi không đồng bộ

class Daemon
{
    public function execute_background( /* model, method, params */ )
    {
        $ci = &get_instance( );
        // The callback URL (its ourselves)
        $parts = parse_url( $ci->config->item( 'base_url' ) . "/daemon" );
        if ( strcmp( $parts['scheme'], 'https' ) == 0 )
        {
            $port = 443;
            $host = "ssl://" . $parts['host'];
        }
        else 
        {
            $port = 80;
            $host = $parts['host'];
        }
        if ( ( $fp = fsockopen( $host, isset( $parts['port'] ) ? $parts['port'] : $port, $errno, $errstr, 30 ) ) === FALSE )
        {
            throw new Exception( "Internal server error: background process could not be started" );
        }
        $ci->load->library( 'encrypt' );
        $post_string = "data=" . urlencode( $ci->encrypt->encode( serialize( func_get_args( ) ) ) );
        $out = "POST " . $parts['path'] . " HTTP/1.1\r\n";
        $out .= "Host: " . $host . "\r\n";
        $out .= "Content-Type: application/x-www-form-urlencoded\r\n";
        $out .= "Content-Length: " . strlen( $post_string ) . "\r\n";
        $out .= "Connection: Close\r\n\r\n";
        $out .= $post_string;
        fwrite( $fp, $out );
        fclose( $fp );
    }
}

Phương thức này có thể được gọi để xử lý bất kỳ mô hình :: method () nào trong 'background'. Nó sử dụng các đối số biến.

$this->load->library('daemon');
$this->daemon->execute_background( 'model', 'method', $arg1, $arg2, ... );

0

Gợi ý: định dạng một trang HTML FRAMESET có chứa 9 khung bên trong. Mỗi khung sẽ NHẬN một "phiên bản" khác nhau của trang myapp.php của bạn. Sẽ có 9 luồng khác nhau chạy song song trên máy chủ Web.


0

Đối với PHP5.5 +, mpyw / co là giải pháp cuối cùng. Nó hoạt động như thể nó là tj / co trong JavaScript.

Thí dụ

Giả sử rằng bạn muốn tải xuống hình đại diện của nhiều người dùng GitHub được chỉ định. Các bước sau là bắt buộc đối với mỗi người dùng.

  1. Nhận nội dung của http://github.com/mpyw (TẢI HTML)
  2. Tìm <img class="avatar" src="...">và yêu cầu nó (NHẬN HÌNH ẢNH)

---: Đang chờ phản hồi của tôi
... : Đang chờ phản hồi khác trong các luồng song song

Nhiều curl_multikịch bản dựa trên nổi tiếng đã cung cấp cho chúng ta các luồng sau.

        /-----------GET HTML\  /--GET IMAGE.........\
       /                     \/                      \ 
[Start] GET HTML..............----------------GET IMAGE [Finish]
       \                     /\                      /
        \-----GET HTML....../  \-----GET IMAGE....../

Tuy nhiên, điều này là không đủ hiệu quả. Bạn có muốn giảm thời gian chờ đợi vô ích ...?

        /-----------GET HTML--GET IMAGE\
       /                                \            
[Start] GET HTML----------------GET IMAGE [Finish]
       \                                /
        \-----GET HTML-----GET IMAGE.../

Có, nó rất dễ dàng với mpyw / co. Để biết thêm chi tiết, hãy truy cập trang kho lưu trữ.


-1

Đây là hàm PHP của riêng tôi khi tôi ĐĂNG đến một URL cụ thể của bất kỳ trang nào ....

Mẫu: * cách sử dụng Hàm của tôi ...

<?php
    parse_str("email=myemail@ehehehahaha.com&subject=this is just a test");
    $_POST['email']=$email;
    $_POST['subject']=$subject;
    echo HTTP_Post("http://example.com/mail.php",$_POST);***

    exit;
?>
<?php
    /*********HTTP POST using FSOCKOPEN **************/
    // by ArbZ

    function HTTP_Post($URL,$data, $referrer="") {

    // parsing the given URL
    $URL_Info=parse_url($URL);

    // Building referrer
    if($referrer=="") // if not given use this script as referrer
      $referrer=$_SERVER["SCRIPT_URI"];

    // making string from $data
    foreach($data as $key=>$value)
      $values[]="$key=".urlencode($value);
    $data_string=implode("&",$values);

    // Find out which port is needed - if not given use standard (=80)
    if(!isset($URL_Info["port"]))
      $URL_Info["port"]=80;

    // building POST-request: HTTP_HEADERs
    $request.="POST ".$URL_Info["path"]." HTTP/1.1\n";
    $request.="Host: ".$URL_Info["host"]."\n";
    $request.="Referer: $referer\n";
    $request.="Content-type: application/x-www-form-urlencoded\n";
    $request.="Content-length: ".strlen($data_string)."\n";
    $request.="Connection: close\n";
    $request.="\n";
    $request.=$data_string."\n";

    $fp = fsockopen($URL_Info["host"],$URL_Info["port"]);
    fputs($fp, $request);
    while(!feof($fp)) {
        $result .= fgets($fp, 128);
    }
    fclose($fp); //$eco = nl2br();

    function getTextBetweenTags($string, $tagname) {
        $pattern = "/<$tagname ?.*>(.*)<\/$tagname>/";
        preg_match($pattern, $string, $matches);
        return $matches[1]; }
    //STORE THE FETCHED CONTENTS to a VARIABLE, because its way better and fast...
    $str = $result;
    $txt = getTextBetweenTags($str, "span"); $eco = $txt;  $result = explode("&",$result);
    return $result[1];
<span style=background-color:LightYellow;color:blue>".trim($_GET['em'])."</span>
</pre> "; 
}
</pre>

-2

Hãy thử mã này ...

$chu = curl_init();

curl_setopt($chu, CURLOPT_URL, 'http://www.myapp.com/test.php?someprm=xyz');

curl_setopt($chu, CURLOPT_FRESH_CONNECT, true);
curl_setopt($chu, CURLOPT_TIMEOUT, 1);

curl_exec($chu);
curl_close($chu);

Vui lòng đừng quên kích hoạt phần mở rộng CURL php.


Bạn có thể đặt CURLOPT_TIMEOUT_MSví dụ: 100 mili giây thay vì tính CURLOPT_TIMEOUTbằng giây và có phút là 1 giây - để thực thi nhanh hơn.
Jason Silver

-5

Điều này hoạt động tốt đối với tôi, đáng buồn là bạn không thể lấy phản hồi từ yêu cầu của mình:

<?php
header("http://mahwebsite.net/myapp.php?var=dsafs");
?>

Nó hoạt động rất nhanh, không cần ổ cắm tcp thô :)


Hàm này thêm tiêu đề vào phản hồi ... nó không gửi yêu cầu tiêu đề. php.net/manual/bg/ Chức năng.header.php
Lachezar Todorov
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.