別のサーバー上の別のスクリプトに単純なGETリクエストを送信したい。どうすればいいですか?
ある場合には、出力を必要とせずに外部スクリプトを要求するだけです。
make_request('http://www.externalsite.com/script1.php?variable=45'); //example usage
2番目の場合、テキスト出力を取得する必要があります。
$output = make_request('http://www.externalsite.com/script2.php?variable=45');
echo $output; //string output
正直に言うと、これは実際にはCURLの仕事ではないので、CURLをいじりたくありません。また、PECL拡張機能がないため、http_getを使用したくありません。
Fsockopenは動作しますか?その場合、ファイルの内容を読み取らずにこれを行うにはどうすればよいですか?他に方法はありませんか?
皆さんありがとう
最初のケースでは、スクリプトが何かを返すのを待ちたくありません。 file_get_contents()はページが完全にロードされるのを待つなどと理解していますか?
file_get_contents
はあなたが望むことをします
$output = file_get_contents('http://www.example.com/');
echo $output;
編集:GET要求を実行してすぐに戻る1つの方法。
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);
}
これは、ソケットを開いて、getリクエストを実行し、すぐにソケットを閉じて戻ることです。
これは、POSTとGETリクエストの両方でMarquisの回答を機能させる方法です。
// $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);
}
更新に関して、ページ全体がロードされるのを待たないことについて-HTTP HEAD
リクエストがあなたが探しているものだと思います。
get_headers これを行う必要があります-ヘッダーのみを要求するため、ページ全体のコンテンツは送信されません。
"PHP/Curl:HEAD一部のサイトではリクエストに時間がかかる" PHP/Curlを使用してHEAD
リクエストを行う方法を説明しています
リクエストをトリガーし、スクリプトをまったく保留しない場合は、複雑さを変えるいくつかの方法があります。
"wget -O /dev/null $carefully_escaped_url"
-これはプラットフォーム固有であり、コマンドにパラメーターをエスケープする場合は本当に注意する必要があります十分にテストすることをお勧めしますPHP library: 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はURLを呼び出すための多くの方法を提供しますが、リクエスト/実行サイクルごとに非同期/スレッド処理を行うためのすぐに使えるサポートは提供しません。 URL(またはSQLステートメントなど)のリクエストはsome種類の応答を待ちます。これを実現するには、ローカルマシンで実行されている何らかの種類のセカンダリシステムが必要です( 「php job queue」をグーグルで検索)
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);
}
興味深い問題。他のサーバーで何らかのプロセスやアクションをトリガーしたいだけなのに、結果がどうであるかは気にせず、スクリプトを続行させたいと思います。おそらくcURLにこれを実現できるものがありますが、exec()
を使用して、cURLが実行できない場合に呼び出しを行うサーバーで別のスクリプトを実行することを検討してください。 (通常、人々はスクリプト呼び出しの結果を望んでいるので、PHPにプロセスをトリガーするだけの能力があるかどうかはわかりません。)exec()
を使用すると、wget
または別のPHP file_get_conents()
でリクエストを行うスクリプト。
Linux環境を使用している場合は、PHPのexecコマンドを使用して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ミリ秒未満で完了することができます。
推奨される方法ではなく、メッセージキューの使用を検討することをお勧めします。これは、単にリクエストを送信するよりも少し多くの仕事が必要ですが、これがより良い解決策になると確信しています。
私のやり方をお見せしましょう:)
サーバーにnodejsをインストールする必要があります
(私のサーバーは1000のhttps get要求を送信するのに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);
}
非同期GETリクエストに関する質問が表示されるのは、何百ものリクエストを実行し、結果データを取得して処理する必要がある状況に遭遇したためです。 request そして、すべてのリクエストには重要なミリ秒の実行が必要です。これは、単純なfile_get_contents
で合計実行の分(!)につながります。
この場合、関数のphp.netで w_haigh の非常に役立つコメントでした 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など。
上記のスクリプトに関するいくつかの修正。次は私のために働いています
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);
}
誰も言及していないようです 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();
}
);
単純な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);
}
試してください:
//Your Code here
$pid = pcntl_fork();
if ($pid == -1) {
die('could not fork');
}
else if ($pid)
{
echo("Bye")
}
else
{
//Do Post Processing
}
これはApacheモジュールとしては機能しません。CGIを使用する必要があります。
提案:たとえば、内部に9つのフレームを含むFRAMESET HTMLページをフォーマットします。各フレームは、myapp.phpページの異なる「インスタンス」を取得します。 Webサーバーでは、9つの異なるスレッドが並行して実行されます。
このスレッドに基づいて、codeigniterプロジェクト用に作成しました。それはうまく機能します。バックグラウンドで処理される関数を使用できます。
非同期呼び出しを受け入れるコントローラー。
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( ) );
}
}
}
そして、非同期呼び出しを行うライブラリ
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()を処理するために呼び出すことができます。可変引数を使用します。
$this->load->library('daemon');
$this->daemon->execute_background( 'model', 'method', $arg1, $arg2, ... );
PHP5.5 +の場合、mpyw/coが究極のソリューションです。 JavaScriptの tj/co のように機能します。
指定した複数のGitHubユーザーのアバターをダウンロードするとします。各ユーザーには次の手順が必要です。
<img class="avatar" src="...">
およびリクエスト(GET IMAGE)---
:応答を待っています...
:並列フローで他の応答を待機しています
多くの有名な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を使用すると非常に簡単です。詳細については、リポジトリのページをご覧ください。