ฉันจะสร้างคำขอ GET แบบอะซิงโครนัสใน PHP ได้อย่างไร


98

ฉันต้องการส่งคำขอ GET อย่างง่ายไปยังสคริปต์อื่นบนเซิร์ฟเวอร์อื่น ฉันต้องทำอย่างไร

ในกรณีหนึ่งฉันเพียงแค่ขอสคริปต์ภายนอกโดยไม่ต้องใช้เอาต์พุตใด ๆ

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

ในกรณีที่สองฉันต้องได้รับเอาต์พุตข้อความ

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

บอกตามตรงว่าฉันไม่อยากยุ่งกับ CURL เพราะนี่ไม่ใช่หน้าที่ของ CURL จริงๆ ฉันไม่ต้องการใช้ประโยชน์จาก http_get เนื่องจากฉันไม่มีส่วนขยาย PECL

fsockopen จะใช้ได้หรือไม่? ถ้าเป็นเช่นนั้นฉันจะทำสิ่งนี้โดยไม่อ่านเนื้อหาของไฟล์ได้อย่างไร ไม่มีวิธีอื่นหรือ

ขอบคุณทุกคน

อัปเดต

ฉันควรเพิ่มในกรณีแรกฉันไม่ต้องการรอให้สคริปต์ส่งคืนอะไร ตามที่ฉันเข้าใจ file_get_contents () จะรอให้เพจโหลดจนเสร็จ ฯลฯ ?


6
@ วิลเลียม: ใช่คำถามส่วนใหญ่ถือได้ว่าซ้ำกันแน่นอน 8-) ฉันคิดว่าคุณโพสต์ลิงค์ผิด ...
RichieHindle


1
ฉันตั้งใจจะโพสต์ลิงค์ musicfreak ที่โพสต์ผสมแท็บของฉัน ;-)
William Brendel

2
@ ริชชี่: คำถามส่วนใหญ่ ? ;)
Sasha Chedygov

1
ฉันตั้งชื่อคำถามใหม่เพื่อแยกความแตกต่างจากคำถามอื่นเนื่องจากดูเหมือนว่าคุณต้องการส่งคำขอโดยไม่สนใจเกี่ยวกับการใช้การตอบกลับ (ดังนั้นจึงสามารถเกิดขึ้นได้เมื่อสคริปต์ที่เหลือทำงาน) เปลี่ยนกลับถ้าฉันเข้าใจผิด!
dbr

คำตอบ:


52

file_get_contents จะทำในสิ่งที่คุณต้องการ

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

แก้ไข: วิธีหนึ่งในการเริ่มต้นคำขอ GET และส่งคืนทันที

อ้างจาก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);
}

สิ่งนี้คือเปิดซ็อกเก็ตดับคำขอรับและปิดซ็อกเก็ตทันทีและส่งคืน


6
curl_post_async ส่งคำขอ POST ไม่ใช่ GET
Vinko Vrsalovic

13
ฉันพูดถูกหรือเปล่าว่าฟังก์ชันนี้ตั้งชื่อไม่ถูกต้อง มันไม่ได้เกี่ยวข้องอะไรกับห้องสมุด curl มันเป็น fsock_post_async () มากกว่า
MikeMurko

62
นี่ไม่ใช่ async! โดยเฉพาะอย่างยิ่งหากเซิร์ฟเวอร์ในอีกด้านหนึ่งลงโค้ดส่วนนี้จะแฮงค์เป็นเวลา 30 วินาที (พารามิเตอร์ที่ 5 ใน fsockopen) นอกจากนี้ fwrite จะใช้เวลาอันแสนหวานในการดำเนินการ (ซึ่งคุณสามารถ จำกัด ด้วย stream_set_timeout ($ fp, $ my_timeout) สิ่งที่ดีที่สุดที่คุณสามารถทำได้คือตั้งค่าระยะหมดเวลาต่ำใน fsockopen เป็น 0.1 (100ms) และ $ my_timeout ถึง 100ms คุณยอมเสี่ยงว่าการขอหมดเวลา
Chris Cinelli

4
สิ่งนี้ไม่เกี่ยวข้องกับ async นี่คือการซิงค์ตามที่ได้รับ ... Async หมายถึงทำงานอื่น ๆ ในขณะที่งานนี้กำลังเสร็จสิ้น เป็นการดำเนินการแบบขนาน
CodeAngry

17
นี่ไม่ใช่ async หรือไม่ใช้ curl คุณกล้าเรียกมันcurl_post_asyncและได้รับคะแนนโหวตมากขึ้น ...
Daniel W.

33

นี่คือวิธีทำให้คำตอบของ Marquis ทำงานร่วมกับคำขอ POST และ 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
นี่เป็นข้อมูลโค้ดที่ใช้งานง่ายและฉันเคยใช้ที่นี่และที่นั่น แต่ตอนนี้ฉันพบว่าฉันต้องทำสิ่งเดียวกัน แต่ด้วยไซต์ SSL มีอะไรที่ฉันต้องการเปลี่ยนแปลงนอกเหนือจากประเภท HTTP / 1.1 และพอร์ตหรือไม่
Kevin Jhangiani

2
ในการตอบคำถามเกี่ยวกับการใช้ SSL นี้คุณสามารถทำให้เป็น SSL ได้โดยเปลี่ยนพอร์ตเป็น 443 และต่อท้าย ssl: // ที่ชื่อพอร์ตใน fsockopen: $ fp = fsockopen ("ssl: //". $ parts ['host '],
Michael Dogger

1
"มีอะไรที่ฉันต้องการเปลี่ยนแปลงนอกเหนือจากประเภท HTTP / 1.1 และพอร์ตหรือไม่" - ใช่คุณควรเรียก fsockopen () ด้วยชื่อโฮสต์ssl://hostnameแทน just hostname.
Cowlby

22
นี่ไม่ใช่ async! โดยเฉพาะอย่างยิ่งหากเซิร์ฟเวอร์ในอีกด้านหนึ่งลงโค้ดส่วนนี้จะแฮงค์เป็นเวลา 30 วินาที (พารามิเตอร์ที่ 5 ใน fsockopen) นอกจากนี้ fwrite จะใช้เวลาอันแสนหวานในการดำเนินการ (ซึ่งคุณสามารถ จำกัด ด้วย stream_set_timeout ($ fp, $ my_timeout) สิ่งที่ดีที่สุดที่คุณสามารถทำได้คือตั้งค่าระยะหมดเวลาต่ำใน fsockopen เป็น 0.1 (100ms) และ $ my_timeout ถึง 100ms คุณยอมเสี่ยงว่าการขอหมดเวลา
Chris Cinelli

1
ไม่ควรตั้งค่าความยาวของเนื้อหาสำหรับ GET บางทีในบางสถานการณ์อาจไม่ทำให้เกิดข้อผิดพลาด แต่ในกรณีของฉันส่งผลให้คำขอไม่ถูกประมวลผลโดยสคริปต์ php ที่เรียกว่า
user3285954

13

เกี่ยวกับการอัปเดตของคุณเกี่ยวกับการไม่ต้องการรอให้หน้าเต็มโหลด - ฉันคิดว่าHEADคำขอHTTP คือสิ่งที่คุณกำลังมองหา ..

get_headersควรทำสิ่งนี้ - ฉันคิดว่ามันขอเฉพาะส่วนหัวเท่านั้นดังนั้นจะไม่ถูกส่งเนื้อหาแบบเต็มหน้า

"PHP / Curl: HEAD Request ใช้เวลานานในบางไซต์"อธิบายวิธีการHEADส่งคำขอโดยใช้ PHP / Curl

หากคุณต้องการทริกเกอร์คำขอและไม่ถือสคริปต์เลยมีหลายวิธีที่มีความซับซ้อนแตกต่างกันไป ..

  • ดำเนินการตามคำขอ HTTP เป็นกระบวนการพื้นหลังphp ดำเนินการกระบวนการพื้นหลัง - โดยทั่วไปคุณจะดำเนินการบางอย่างเช่น"wget -O /dev/null $carefully_escaped_url"นี้จะเป็นแพลตฟอร์มเฉพาะและคุณต้องระวังอย่างมากเกี่ยวกับการหลีกเลี่ยงพารามิเตอร์ไปยังคำสั่ง
  • การเรียกใช้สคริปต์ PHP ในพื้นหลัง - โดยทั่วไปเหมือนกับวิธีการของ UNIX แต่เรียกใช้สคริปต์ PHP แทนคำสั่งเชลล์
  • มี "คิวงาน" โดยใช้ฐานข้อมูล (หรือบางอย่างเช่นฝักถั่วซึ่งมีโอกาสมากเกินไป) คุณเพิ่ม URL ลงในคิวและกระบวนการเบื้องหลังหรือ cron-job ตรวจหางานใหม่เป็นประจำและดำเนินการตามคำขอบน URL

+1 สำหรับตัวเลือกที่น่าสนใจต่างๆที่ฉันไม่เคยคิดมาก่อน
Jasdeep Khalsa

"ฉันคิดว่าขอแค่ส่วนหัวเท่านั้น" - บางที แต่ไม่มีอะไรที่จะหยุดเอกสารไม่ให้ส่งเนื้อหาตอบกลับแบบเต็มตามคำขอ HEAD และฉันคิดว่าวิธีนี้จะใช้ fsock ใต้ฝากระโปรงและบังคับให้รอ (และอ่าน) การตอบสนองทั้งหมด
hiburn8

6

คุณไม่ทำ แม้ว่า PHP จะมีหลายวิธีในการเรียก URL แต่ก็ไม่ได้ให้การสนับสนุนนอกกรอบสำหรับการประมวลผลแบบอะซิงโครนัส / เธรดใด ๆ ต่อคำขอ / รอบการดำเนินการ วิธีการใด ๆ ในการส่งคำขอ URL (หรือคำสั่ง SQL หรืออื่น ๆ ) จะรอการตอบสนองบางอย่าง คุณจะต้องมีระบบรองบางประเภทที่ทำงานบนเครื่องท้องถิ่นเพื่อให้บรรลุสิ่งนี้ (google สำหรับ "php job que")


1
มีการแฮ็คที่นี่: stackoverflow.com/questions/124462/asynchronous-php-calls (ตอบโดย Christian Davén) แต่ฉันยอมรับว่าคิวจะเป็นวิธีที่ถูกต้อง
Chris Cinelli

ฉันคิดว่าคำตอบจากปี 2009 นี้ล้าสมัยแล้ว ห้องสมุดล่อ PHPในขณะนี้มีการสนับสนุนสำหรับการทำคำขอพร้อมกันและไม่ตรงกัน
Simon East

6

ฉันอยากจะแนะนำให้คุณทดสอบไลบรารี PHP ที่ดี: 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
}

ห้องสมุดล่อ PHPยังมีการสนับสนุนสำหรับการทำคำขอพร้อมกันและไม่ตรงกัน
Simon East

Guzzle อ้างว่าได้รับการสนับสนุน แต่การทดสอบวิธี postAsync ดูเหมือนว่า 150 ms พร้อมกันและ 2 ms แบบอะซิงโครนัส ฉันใช้เวลามากกว่าหนึ่งชั่วโมงในการพยายามแก้ไขโดยไม่ประสบความสำเร็จ - ไม่แนะนำ
Velizar Hristov

4

หากคุณใช้สภาพแวดล้อม Linux คุณสามารถใช้คำสั่ง exec ของ PHP เพื่อเรียกใช้ linux curl นี่คือโค้ดตัวอย่างซึ่งจะสร้างโพสต์ HTTP แบบอะซิงโครนัส

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

รหัสนี้ไม่จำเป็นต้องมี PHP libs เพิ่มเติมและสามารถโพสต์ http ให้เสร็จสมบูรณ์ได้ภายในเวลาไม่ถึง 10 มิลลิวินาที


1
นี่เป็นความคิดที่แย่มาก: exec ล้มเหลวมาก: ลองนึกดูว่าลูกค้า 6/200 รายจะไม่ได้รับอีเมลยืนยันการจองแบบชำระเงิน ...
HellBaby

สิ่งนี้ใช้ได้ผลสำหรับฉันเท่าที่ฉันต้องการ ping เพื่อเริ่มสคริปต์อื่นบนเซิร์ฟเวอร์อื่น ฉันเพิ่งใช้แบบนั้น: _async_http_post ($ url, ''); และนี่กำลังทำงานบนเซิร์ฟเวอร์ OVH ซึ่งกันและกัน ... ซึ่งดีมาก
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);
}

คุณสามารถทำให้มันกลับวัตถุซึ่งช่วยให้คุณเรียกgetstatus()หรือหรือwaitSend() waitResult()ด้วยวิธีนี้ผู้โทรสามารถรับพฤติกรรม async ได้อย่างสมบูรณ์โดยการโทรวนซ้ำเพื่อตรวจสอบว่ามีผลลัพธ์หรือไม่และถ้าไม่ดำเนินการต่อไปยังงานอื่นที่กำลังทำงานอยู่ อืมตอนนี้ฉันต้องการพอร์ตTaskจาก. net เป็น php …
binki

3

ปัญหาที่น่าสนใจ ฉันเดาว่าคุณต้องการเรียกใช้กระบวนการหรือการดำเนินการบางอย่างบนเซิร์ฟเวอร์อื่น แต่ไม่สนใจว่าผลลัพธ์จะเป็นอย่างไรและต้องการให้สคริปต์ของคุณดำเนินการต่อ อาจมีบางอย่างใน cURL ที่สามารถทำให้สิ่งนี้เกิดขึ้นได้ แต่คุณอาจต้องการพิจารณาใช้exec()เพื่อเรียกใช้สคริปต์อื่นบนเซิร์ฟเวอร์ที่เรียกใช้หาก cURL ไม่สามารถทำได้ (โดยปกติคนที่ต้องการผลของการโทรสคริปต์ดังนั้นฉันไม่แน่ใจว่าถ้า PHP มีความสามารถในการที่จะเพียงแค่เรียกกระบวนการ.) ด้วยexec()คุณสามารถเรียกใช้wgetหรือแม้กระทั่งสคริปต์ PHP file_get_conents()อื่นที่ทำให้การร้องขอด้วย


2

คุณควรพิจารณาใช้คิวข้อความแทนวิธีการที่แนะนำ ฉันแน่ใจว่านี่จะเป็นทางออกที่ดีกว่าแม้ว่าจะต้องใช้งานมากกว่าการส่งคำขอก็ตาม


2

ให้ฉันแสดงวิธีของฉัน :)

ต้องการ nodejs ที่ติดตั้งบนเซิร์ฟเวอร์

(เซิร์ฟเวอร์ของฉันส่งคำขอรับ https 1,000 รายการใช้เวลาเพียง 2 วินาที)

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
นี่ไม่ใช่โซลูชัน PHP ที่บริสุทธิ์
binki

2

สำหรับฉันคำถามเกี่ยวกับคำขอ GET แบบอะซิงโครนัสปรากฏขึ้นเนื่องจากฉันพบกับสถานการณ์เมื่อฉันต้องทำหลายร้อยคำขอรับและจัดการกับข้อมูลผลลัพธ์ในทุกคำขอและทุกคำขอใช้เวลาในการดำเนินการอย่างมีนัยสำคัญซึ่งนำไปสู่นาที (!) การดำเนินการทั้งหมดด้วยวิธีง่ายๆfile_get_contentsรวมการดำเนินการด้วยง่าย

ในกรณีนี้มันเป็นความคิดเห็นที่มีประโยชน์มากของw_haighที่ php.net เกี่ยวกับฟังก์ชันhttp://php.net/manual/en/function.curl-multi-init.php

ดังนั้นนี่คือเวอร์ชันอัปเกรดและทำความสะอาดของฉันในการส่งคำขอจำนวนมากพร้อมกัน สำหรับกรณีของฉันมันเทียบเท่ากับวิธี "อะซิงโครนัส" อาจจะช่วยใครบางคนก็ได้!

// 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

เป็นเรื่องง่ายที่จะเขียนสิ่งนี้ใหม่เพื่อจัดการกับ POST หรือคำขอ HTTP (S) ประเภทอื่น ๆ หรือชุดค่าผสมใด ๆ และการสนับสนุน Cookie การเปลี่ยนเส้นทาง http-auth ฯลฯ


โอ้ .. ฉันเห็นคำถามที่สร้างขึ้นในปี 2009 และฉันเขียนคำตอบของฉันในปี 2016 :) แต่พวกเราหลายคน google php ได้รับ asynchronousและมาที่นี่
FlameStorm

ใช่ฉันมาที่นี่ด้วยเมื่อ Googling ผู้เขียนโค้ดบางรายอาจต้องการดูไลบรารี Guzzle PHPซึ่งรองรับการร้องขอพร้อมกันและแบบอะซิงโครนัส
Simon East

1

ลอง:

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

สิ่งนี้จะไม่ทำงานเป็นโมดูล apache คุณต้องใช้ CGI


1

ฉันพบลิงค์ที่น่าสนใจนี้เพื่อทำการประมวลผลแบบอะซิงโครนัส (รับคำขอ)

askapache

นอกจากนี้คุณสามารถประมวลผลแบบอะซิงโครนัสได้โดยใช้คิวข้อความเช่น beanstalkd


1

นี่คือการปรับเปลี่ยนคำตอบที่ยอมรับสำหรับการดำเนินการตามคำขอ GET อย่างง่าย

สิ่งหนึ่งที่ควรทราบหากเซิร์ฟเวอร์ทำการเขียน url ใหม่สิ่งนี้จะไม่ทำงาน คุณจะต้องใช้ไคลเอ็นต์ http ที่มีคุณลักษณะครบถ้วนมากขึ้น

  /**
   * 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

การแก้ไขสคริปต์ที่โพสต์ไว้ด้านบนเพียงเล็กน้อย ต่อไปนี้กำลังทำงานให้ฉัน

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

ฉันมีปัญหาโดยที่ fwrite ส่งคืนจำนวนไบต์ที่เป็นบวก แต่ไม่ได้เรียกจุดสิ้นสุดของสคริปต์ (ไม่ได้บันทึก) .. ใช้ได้เฉพาะเมื่อฉันใช้: while (! feof ($ fp)) {fgets ($ fp , 128); }
มิเกล

1

ดูเหมือนจะไม่มีใครพูดถึงGuzzleซึ่งเป็นไคลเอนต์ PHP HTTP ที่ช่วยให้ส่งคำขอ HTTP ได้ง่าย สามารถทำงานโดยมีหรือไม่มีCurlก็ได้ สามารถส่งคำขอทั้งแบบซิงโครนัสและอะซิงโครนัส

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

ใช่หลายคำตอบในหัวข้อนี้ค่อนข้างเก่า แต่ Guzzle เป็นตัวเลือกที่ดีที่สุดที่ฉันเคยเจอในปี 2018 ขอบคุณสำหรับการโพสต์
Simon East

0

จากหัวข้อนี้ฉันทำสิ่งนี้สำหรับโครงการ codeigniter ของฉัน มันใช้งานได้ดี คุณสามารถประมวลผลฟังก์ชันใด ๆ ในพื้นหลังได้

คอนโทรลเลอร์ที่ยอมรับการโทรแบบ async

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

และไลบรารีที่เรียก async

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

วิธีนี้สามารถเรียกใช้เพื่อประมวลผล model :: method () ใดก็ได้ใน 'background' ใช้อาร์กิวเมนต์ตัวแปร

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

0

คำแนะนำ: จัดรูปแบบหน้า HTML FRAMESET ซึ่งมี 9 เฟรมอยู่ข้างใน แต่ละเฟรมจะได้รับ "อินสแตนซ์" ที่แตกต่างกันของหน้า myapp.php ของคุณ จะมีเธรดที่แตกต่างกัน 9 เธรดที่ทำงานบนเว็บเซิร์ฟเวอร์ควบคู่กันไป


0

สำหรับ PHP5.5 + mpyw / coเป็นทางออกที่ดีที่สุด มันทำงานราวกับว่าเป็นtj / coใน JavaScript

ตัวอย่าง

สมมติว่าคุณต้องการดาวน์โหลดอวตารของผู้ใช้ GitHub ที่ระบุหลายตัว ขั้นตอนต่อไปนี้จำเป็นสำหรับผู้ใช้แต่ละคน

  1. รับเนื้อหาของhttp://github.com/mpyw (รับ HTML)
  2. ค้นหา<img class="avatar" src="...">และร้องขอ (รับภาพ)

---: รอคำตอบของฉัน
... : กำลังรอคำตอบอื่น ๆ ในโฟลว์คู่ขนาน

curl_multiสคริปต์ที่มีชื่อเสียงหลายฉบับได้ให้ขั้นตอนต่อไปนี้แก่เราแล้ว

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

อย่างไรก็ตามสิ่งนี้ไม่มีประสิทธิภาพเพียงพอ คุณต้องการลดเวลารอที่ไร้ค่า...หรือไม่?

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

ใช่มันง่ายมากกับ mpyw / co สำหรับรายละเอียดเพิ่มเติมโปรดไปที่เพจที่เก็บ


-1

นี่คือฟังก์ชัน PHP ของฉันเองเมื่อฉันโพสต์ไปยัง URL เฉพาะของหน้าใด ๆ ....

ตัวอย่าง: *การใช้งานฟังก์ชันของฉัน ...

<?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

ลองรหัสนี้ ....

$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);

โปรดอย่าลืมเปิดใช้งานส่วนขยาย CURL php


คุณสามารถตั้งค่าCURLOPT_TIMEOUT_MSเช่น 100 มิลลิวินาทีแทนที่จะCURLOPT_TIMEOUTเป็นวินาทีและมีเวลาอย่างน้อย 1 วินาทีเพื่อให้การดำเนินการเร็วขึ้น
Jason Silver

-5

วิธีนี้ใช้ได้ผลสำหรับฉันน่าเสียดายที่คุณไม่สามารถเรียกคืนการตอบสนองจากคำขอของคุณ

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

ทำงานได้เร็วมากไม่จำเป็นต้องใช้ซ็อกเก็ต tcp ดิบ :)


ฟังก์ชั่นนี้จะเพิ่มส่วนหัวในการตอบกลับ ... มันไม่ได้ส่งคำขอส่วนหัว php.net/manual/bg/function.header.php
Lachezar Todorov
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.