Jak utworzyć asynchroniczne żądanie GET w PHP?

97

Chciałbym wysłać proste żądanie GET do innego skryptu na innym serwerze. Jak mam to zrobic?

W jednym przypadku wystarczy, że zażądam zewnętrznego skryptu bez potrzeby wyświetlania jakichkolwiek danych wyjściowych.

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

W drugim przypadku muszę uzyskać wynik tekstowy.

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

Szczerze mówiąc, nie chcę bawić się CURL, ponieważ tak naprawdę nie jest to zadanie CURL. Nie chcę również korzystać z http_get, ponieważ nie mam rozszerzeń PECL.

Czy fsockopen zadziała? Jeśli tak, jak mam to zrobić bez wczytywania zawartości pliku? Czy nie ma innego wyjścia?

Dziękuje wszystkim

Aktualizacja

Dodam, że w pierwszym przypadku nie chcę czekać, aż skrypt coś zwróci. Jak rozumiem, file_get_contents () będzie czekać na pełne załadowanie strony itp.?

Abs
źródło
6
@William: Tak, większość pytań można uznać za ich dokładne duplikaty. 8-) Myślę, że zamieściłeś zły link ...
RichieHindle
Duplikat: stackoverflow.com/questions/959063/…
Sasha Chedygov
1
Miałem zamiar opublikować link opublikowany przez musicfreak, pomieszałem moje zakładki ;-)
William Brendel,
2
@Richie: Większość pytań? ;)
Sasha Chedygov
1
Zmieniłem tytuł pytania, aby odróżnić je od innych, ponieważ wydaje się, że chcesz, aby żądanie nie przejmowało się używaniem odpowiedzi (więc może się to zdarzyć, gdy reszta skryptu zostanie uruchomiona). Przywróć, jeśli się mylę!
dbr

Odpowiedzi:

52

file_get_contents zrobisz, co chcesz

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

Edycja: jeden sposób na odpalenie żądania GET i natychmiastowy powrót.

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

To co robi to otwarcie gniazda, odpalenie żądania get i natychmiastowe zamknięcie gniazda i zwrócenie.

Marquis Wang
źródło
6
curl_post_async wysyła żądanie POST, a nie GET.
Vinko Vrsalovic
13
Czy mam rację mówiąc, że ta funkcja ma niewłaściwą nazwę? To naprawdę nie ma nic wspólnego z biblioteką curl. To bardziej przypomina fsock_post_async ()
MikeMurko
61
To NIE jest asynchroniczne! W szczególności, jeśli serwer po drugiej stronie jest wyłączony, ten fragment kodu zawiesi się na 30 sekund (piąty parametr w fsockopen). Również fwrite zajmie swój słodki czas na wykonanie (możesz to ograniczyć za pomocą stream_set_timeout ($ fp, $ my_timeout). Najlepsze co możesz zrobić to ustawić niski limit czasu dla fsockopen na 0.1 (100ms) i $ my_timeout na 100ms Ryzykujesz jednak, że przekroczenie limitu czasu żądania
Chris Cinelli,
4
Nie ma to nic wspólnego z async. To jest tak samo zsynchronizowane, jak to tylko możliwe ... Async oznacza wykonywanie innych zadań podczas wykonywania tego zadania. To równoległe wykonanie.
CodeAngry
17
To nie jest ani asynchroniczne, ani nie używa curl, jak odważysz się to nazwać curl_post_asynci zdobyć nawet pozytywne głosy ...
Daniel W.
33

Oto jak sprawić, by odpowiedź Marquis działała zarówno z żądaniami POST, jak i 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);
  }
catgofire
źródło
2
To jest przydatny fragment kodu i używam go tu i tam, ale teraz stwierdzam, że muszę zrobić to samo, ale z witryną SSL. Czy jest coś, co muszę zmienić oprócz typu HTTP / 1.1 i portu?
Kevin Jhangiani,
2
W odpowiedzi na pytanie o używanie tego dla SSL możesz uczynić go SSL, zmieniając port na 443 i dodając ssl: // do nazwy portu w fsockopen: $ fp = fsockopen ("ssl: //". $ Parts ['host '],
Michael Dogger,
1
„Czy jest coś, co muszę zmienić oprócz typu HTTP / 1.1 i portu?” - Tak, powinieneś wywołać fsockopen () z nazwą hosta ssl://hostnamezamiast po prostu hostname.
Cowlby
22
To NIE jest asynchroniczne! W szczególności, jeśli serwer po drugiej stronie jest wyłączony, ten fragment kodu zawiesi się na 30 sekund (piąty parametr w fsockopen). Również fwrite zajmie swój słodki czas na wykonanie (możesz to ograniczyć za pomocą stream_set_timeout ($ fp, $ my_timeout). Najlepsze co możesz zrobić to ustawić niski limit czasu dla fsockopen na 0.1 (100ms) i $ my_timeout na 100ms Ryzykujesz jednak, że przekroczenie limitu czasu żądania
Chris Cinelli,
1
Content-Length nie powinno być ustawione dla GET. Może w niektórych scenariuszach nie powoduje błędów, ale w moim przypadku spowodowało, że żądanie nie było przetwarzane przez skrypt php.
user3285954
13

Jeśli chodzi o twoją aktualizację, nie chcesz czekać na załadowanie całej strony - myślę, że HEADszukasz żądania HTTP .

get_headers powinno to zrobić - myślę, że żąda tylko nagłówków, więc nie zostanie wysłana pełna zawartość strony.

„PHP / Curl: Żądanie HEAD zajmuje dużo czasu w niektórych witrynach” opisuje, jak wykonać HEADżądanie za pomocą PHP / Curl

Jeśli chcesz wywołać żądanie, a nie wstrzymywać skryptu w ogóle, istnieje kilka sposobów o różnym stopniu złożoności.

  • Wykonaj żądanie HTTP jako proces w tle, php uruchom proces w tle - w zasadzie wykonasz coś takiego "wget -O /dev/null $carefully_escaped_url"- będzie to specyficzne dla platformy i musisz bardzo uważać na ucieczkę parametrów do polecenia
  • Wykonywanie skryptu PHP w tle - w zasadzie to samo, co metoda procesu UNIX, ale wykonanie skryptu PHP zamiast polecenia powłoki
  • Miej „kolejkę zadań”, korzystając z bazy danych (lub czegoś takiego jak beanstalkd, co jest prawdopodobnie przesadą). Dodajesz adres URL do kolejki, a proces w tle lub zadanie cron rutynowo sprawdza, czy są nowe zadania i wykonuje żądania na adresie URL
dbr
źródło
+1 za różne interesujące opcje, o których wcześniej nie myślałem
Jasdeep Khalsa
„Myślę, że żąda tylko nagłówków” - być może, ale nic nie stoi na przeszkodzie, aby dokument wysłał pełną treść odpowiedzi w odpowiedzi na żądanie HEAD. I zakładam, że ta metoda użyłaby fsock pod maską i zmusiłaby ją do czekania (i przeczytania) pełnej odpowiedzi.
hiburn8
6

Ty nie. Chociaż PHP oferuje wiele sposobów wywoływania adresu URL, nie oferuje standardowej obsługi wykonywania jakiegokolwiek przetwarzania asynchronicznego / wątkowego na cykl żądania / wykonania. Każda metoda wysłania żądania adresu URL (lub instrukcji SQL, itp.) Będzie czekać na jakąś odpowiedź. Aby to osiągnąć, będziesz potrzebować jakiegoś dodatkowego systemu działającego na komputerze lokalnym (wyszukaj „kolejkę zadań php”)

Alan Storm
źródło
1
Tu jest hack: stackoverflow.com/questions/124462/asynchronous-php-calls (odpowiedź Christiana Davéna), ale zgadzam się, że kolejka byłaby właściwym sposobem na zrobienie tego.
Chris Cinelli,
Myślę, że ta odpowiedź z 2009 roku jest już nieaktualna. Biblioteka chlać PHP posiada teraz wsparcie dla prowadzenia jednoczesnych i asynchronicznych żądań.
Simon East,
6

Polecam dobrze przetestowaną bibliotekę PHP: łatwe w zwijaniu

<?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
}
styl
źródło
Biblioteka chlać PHP posiada również wsparcie dla prowadzenia jednoczesnych i asynchronicznych żądań.
Simon East,
Guzzle twierdzi, że ma wsparcie, ale testowanie jego metody postAsync wygląda tak, jakby robiło to 150 ms synchronicznie, a następnie 2 ms asynchronicznie. Spędziłem ponad godzinę próbując to naprawić bez powodzenia - nie poleciłbym tego.
Velizar Hristov
4

Jeśli używasz środowiska Linux, możesz użyć polecenia exec w PHP, aby wywołać curl linux. Oto przykładowy kod, który utworzy asynchroniczny post 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;
}

Ten kod nie wymaga żadnych dodatkowych bibliotek PHP i może zakończyć wysyłanie wiadomości http w mniej niż 10 milisekund.

Nieznajomy
źródło
1
to jest bardzo zły pomysł: exec bardzo zawodzi: wyobraź sobie, że klienci 6/200 nie otrzymają potwierdzenia e-mailowego dla opłaconej rezerwacji ...
HellBaby
U mnie to zadziałało, ponieważ potrzebuję tylko polecenia ping, aby uruchomić kolejny skrypt na innym serwerze. Po prostu użyłem tego w ten sposób: _async_http_post ($ url, ''); A to działa na wzajemnych serwerach OVH ... Co jest świetne.
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);
}
amez
źródło
Możesz sprawić, że zwróci obiekt, który pozwoli ci wywołać getstatus()lub waitSend()lub waitResult(). W ten sposób obiekt wywołujący może uzyskać zachowanie w pełni asynchroniczne, wywołując pętlę w celu sprawdzenia, czy są wyniki, a jeśli nie, kontynuuje dowolne inne uruchomione zadanie. Hmm, teraz chcę przenieść Taskz .net do php…
binki
3

Ciekawy problem. Domyślam się, że chcesz po prostu uruchomić jakiś proces lub akcję na innym serwerze, ale nie obchodzi cię, jakie są wyniki i chcesz, aby twój skrypt kontynuował. Prawdopodobnie w cURL jest coś, co może to spowodować, ale możesz rozważyć użycie exec()do uruchomienia innego skryptu na serwerze, który wykonuje wywołanie, jeśli cURL nie może tego zrobić. (Zwykle ludzie chcą wyników wywołania skryptu, więc nie jestem pewien, czy PHP ma możliwość po prostu wyzwolenia procesu.) Za pomocą exec()można uruchomić wgetlub nawet inny skrypt PHP, który wysyła żądanie za pomocą file_get_conents().

Darryl Hein
źródło
2

Lepiej rozważ użycie kolejki wiadomości zamiast zalecanych metod. Na pewno będzie to lepsze rozwiązanie, choć wymaga trochę więcej pracy niż samo wysłanie zapytania.

mra214
źródło
2

pokażę ci moją drogę :)

wymaga zainstalowania nodejs na serwerze

(mój serwer wysyła 1000 https żądanie pobrania zajmuje tylko 2 sekundy)

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);
}
user1031143
źródło
1
To nie jest czyste rozwiązanie PHP.
binki
2

U mnie pojawiło się pytanie o asynchroniczne żądanie GET, ponieważ spotkałem się z sytuacją, w której muszę wykonać setki żądań , pobrać i obsłużyć dane wynikowe na każdym żądaniu, a każde żądanie zajmuje znaczące milisekundy wykonania, co prowadzi do minut (!) całkowite wykonanie z prostym file_get_contents.

W tym przypadku bardzo pomocny był komentarz w_haigh na php.net o funkcji http://php.net/manual/en/function.curl-multi-init.php

Oto moja ulepszona i oczyszczona wersja wykonywania wielu żądań jednocześnie. W moim przypadku jest to równoznaczne ze sposobem „asynchronicznym”. Może to komuś pomoże!

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

Łatwo jest to przepisać, aby obsługiwać POST lub inne typy żądań HTTP (S) lub dowolną ich kombinację. Obsługa plików cookie, przekierowania, http-auth itp.

FlameStorm
źródło
Ohh .. Widzę pytanie utworzone w 2009 roku, a swoją odpowiedź piszę w 2016 roku :) Ale wielu z nas google php robi się asynchronicznie i przyszło tutaj.
FlameStorm
Tak, też tu przyjechałem, kiedy googlem. Niektórzy programiści mogą również chcieć zajrzeć do biblioteki PHP Guzzle, która obsługuje wykonywanie współbieżnych i asynchronicznych żądań.
Simon East,
1

Próbować:

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

To NIE zadziała jako moduł Apache, musisz używać CGI.

LM.
źródło
1

Znalazłem ten interesujący link do przetwarzania asynchronicznego (żądanie pobrania).

askapache

Co więcej, możesz wykonywać asynchroniczne przetwarzanie, używając kolejki komunikatów, takiej jak na przykład beanstalkd.

Alfred
źródło
1

Oto adaptacja zaakceptowanej odpowiedzi na wykonanie prostego żądania GET.

Należy pamiętać, że jeśli serwer przepisuje adresy URL, to nie zadziała. Musisz użyć bardziej funkcjonalnego klienta 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);
  }
blak3r
źródło
1

Tylko kilka poprawek do skryptów zamieszczonych powyżej. Poniższe działa dla mnie

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);
    }
A23
źródło
Mam problem, w którym fwrite zwraca dodatnią liczbę bajtów, ale punkt końcowy skryptu nie jest wywoływany (nie rejestruje) .. działa tylko wtedy, gdy używam: while (! Feof ($ fp)) {fgets ($ fp 128); }
Miguel
1

Wydaje się, że nikt nie wspomina o Guzzle , która jest klientem PHP HTTP, który ułatwia wysyłanie żądań HTTP. Może działać z lub bez Curl. Może wysyłać zarówno żądania synchroniczne, jak i asynchroniczne.

$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();
    }
);
zstate
źródło
Tak, wiele odpowiedzi w tym wątku jest dość starych, ale Guzzle to zdecydowanie najlepsza opcja, z jaką spotkałem się w 2018 roku, dzięki za opublikowanie.
Simon East,
0

Na podstawie tego wątku zrobiłem to dla mojego projektu CodeIgniter. Działa dobrze. Możesz mieć dowolną funkcję przetwarzaną w tle.

Kontroler, który akceptuje wywołania asynchroniczne.

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

I bibliotekę, która wykonuje wywołania asynchroniczne

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

Tę metodę można wywołać w celu przetworzenia dowolnego model :: method () w 'tle'. Używa zmiennych argumentów.

$this->load->library('daemon');
$this->daemon->execute_background( 'model', 'method', $arg1, $arg2, ... );
Patrick Savalle
źródło
0

Sugestia: sformatuj stronę FRAMESET HTML, która zawiera, powiedzmy, 9 ramek w środku. Każda ramka POBIERA inną „instancję” Twojej strony myapp.php. Na serwerze WWW będzie działać równolegle 9 różnych wątków.

newbie_dude
źródło
0

W przypadku PHP5.5 + mpyw / co jest najlepszym rozwiązaniem. Działa tak, jakby to było tj / co w JavaScript.

Przykład

Załóżmy, że chcesz pobrać określone awatary wielu użytkowników GitHub. Dla każdego użytkownika wymagane są następujące kroki.

  1. Pobierz zawartość http://github.com/mpyw (GET HTML)
  2. Znajdź <img class="avatar" src="...">i poproś o to (POBIERZ OBRAZ)

---: Oczekiwanie na odpowiedź
...: Oczekiwanie na inną odpowiedź w równoległych przepływach

Wiele znanych curl_multiskryptów bazowych zapewnia nam już następujące przepływy.

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

Jednak nie jest to wystarczająco wydajne. Czy chcesz skrócić bezwartościowy czas oczekiwania ...?

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

Tak, z mpyw / co jest to bardzo łatwe. Aby uzyskać więcej informacji, odwiedź stronę repozytorium.

mpyw
źródło
-1

Oto moja własna funkcja PHP, gdy wykonuję POST na określony adres URL dowolnej strony ...

Przykład: * użycie mojej funkcji ...

<?php
    parse_str("[email protected]&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>
jestem ArbZ
źródło
-2

Wypróbuj ten kod ....

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

Nie zapomnij włączyć rozszerzenia CURL php.

Mukesh
źródło
Możesz ustawić CURLOPT_TIMEOUT_MSnp. 100 milisekund zamiast tego CURLOPT_TIMEOUTw sekundach i min 1 sekundy - dla szybszego wykonania.
Jason Silver
-5

Dla mnie to działa dobrze, niestety nie możesz odzyskać odpowiedzi na swoje żądanie:

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

Działa bardzo szybko, nie ma potrzeby stosowania surowych gniazd tcp :)

D4zk1tty
źródło
Ta funkcja dodaje nagłówek do odpowiedzi ... nie wysyła żądania nagłówka. php.net/manual/bg/function.header.php
Lachezar Todorov