cURL ist ein Tool zum Übertragen von Dateien und Daten mit URL-Syntax, das viele Protokolle unterstützt, einschließlich HTTP, FTP, TELNET und mehr. CURL wurde ursprünglich als Befehlszeilentool entwickelt. Zum Glück ist die cURL-Bibliothek auch von PHP unterstützt. In diesem Artikel werden wir uns einige der erweiterten Funktionen von cURL ansehen und wie wir sie in unseren PHP-Skripts verwenden können.
Es ist wahr, dass es andere Möglichkeiten gibt, den Inhalt einer Webseite abzurufen. Viele Male, hauptsächlich aufgrund von Faulheit, habe ich statt cURL nur einfache PHP-Funktionen verwendet:
$ content = file_get_contents ("http://www.nettuts.com"); // oder $ lines = file ("http://www.nettuts.com"); // oder readfile ("http://www.nettuts.com");
Sie haben jedoch praktisch keine Flexibilität und keine ausreichende Fehlerbehandlung. Außerdem gibt es bestimmte Aufgaben, die Sie einfach nicht erledigen können, z. B. Umgang mit Cookies, Authentifizierung, Formularbeiträge, Dateiuploads usw.
cURL ist eine leistungsfähige Bibliothek, die viele verschiedene Protokolle, Optionen und detaillierte Informationen zu den URL-Anforderungen unterstützt.
Bevor wir uns den komplizierteren Beispielen zuwenden, betrachten wir die grundlegende Struktur einer cURL-Anfrage in PHP. Es gibt vier Hauptschritte:
// 1. initialize $ ch = curl_init (); // 2. Legen Sie die Optionen fest, einschließlich der URL curl_setopt ($ ch, CURLOPT_URL, "http://www.nettuts.com"); curl_setopt ($ ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt ($ ch, CURLOPT_HEADER, 0); // 3. die resultierende HTML-Ausgabe ausführen und abrufen $ output = curl_exec ($ ch); // 4. Löse das Curl-Handle curl_close ($ ch);
Schritt 2 (d. H. Curl_setopt () - Aufrufe) wird ein großer Teil dieses Artikels sein, da dort die ganze Magie stattfindet. Es gibt eine lange Liste von cURL-Optionen, die eingestellt werden können, um die URL-Anforderung detailliert zu konfigurieren. Es kann schwierig sein, die gesamte Liste durchzugehen und alles auf einmal zu verdauen. Daher werden wir heute nur einige der gebräuchlicheren und nützlichsten Optionen in verschiedenen Codebeispielen verwenden.
Optional können Sie auch eine Fehlerprüfung hinzufügen:
//… $ output = curl_exec ($ ch); if ($ output === FALSE) echo "cURL Error:". curl_error ($ ch); //…
Bitte beachten Sie, dass wir zum Vergleich "=== FALSE" anstelle von "== FALSE" verwenden müssen. Denn wir müssen zwischen leerer Ausgabe und dem booleschen Wert FALSE unterscheiden, was auf einen Fehler hinweist.
Ein weiterer optionaler Schritt ist das Abrufen von Informationen zur cURL-Anforderung, nachdem diese ausgeführt wurde.
//… curl_exec ($ ch); $ info = curl_getinfo ($ ch); Echo 'Took'. $ info ['total_time']. 'Sekunden für URL'. $ info ['url']; //…
Folgende Informationen sind im zurückgegebenen Array enthalten:
In diesem ersten Beispiel schreiben wir ein Skript, das URL-Umleitungen anhand verschiedener Browsereinstellungen erkennen kann. Beispielsweise leiten einige Websites Handybrowser oder sogar Surfer aus verschiedenen Ländern um.
Wir werden die Option CURLOPT_HTTPHEADER verwenden, um unsere ausgehenden HTTP-Header einschließlich der Benutzeragentenzeichenfolge und der akzeptierten Sprachen festzulegen. Abschließend überprüfen wir, ob diese Websites versuchen, uns auf andere URLs umzuleiten.
// Test-URLs $ urls = array ("http://www.cnn.com", "http://www.mozilla.com", "http://www.facebook.com"); // test browser $ browsers = array ("standard" => array ("user_agent" => "Mozilla / 5.0 (Windows; U; Windows NT 6.1; de-DE; rv: 1.9.1.6) .6 (.NET CLR 3.5.30729) "," language "=>" de-de, de; q = 0,5 ")," iphone "=> array (" user_agent "=>" Mozilla / 5.0 (iPhone; U ; CPU wie Mac OS X; de) AppleWebKit / 420 + (KHTML, wie Gecko) Version / 3.0 Mobile / 1A537a Safari / 419.3 "," language "=>" de ")," french "=> array (" user_agent ") => "Mozilla / 4.0 (kompatibel; MSIE 7.0; Windows NT 5.1; GTB6; .NET CLR 2.0.50727)", "Sprache" => "fr, fr-FR; q = 0,5")); foreach ($ urls as $ url) echo "URL: $ url \ n"; foreach ($ browser als $ test_name => $ browser) $ ch = curl_init (); // set url curl_setopt ($ ch, CURLOPT_URL, $ url); // Browserspezifische Header setzen curl_setopt ($ ch, CURLOPT_HTTPHEADER, array ("User-Agent: $ browser ['user_agent']", "Accept-Language: $ browser ['language']")); // wir wollen nicht den Seiteninhalt curl_setopt ($ ch, CURLOPT_NOBODY, 1); // wir benötigen den zurückgegebenen HTTP-Header curl_setopt ($ ch, CURLOPT_HEADER, 1); // die Ergebnisse zurückgeben anstatt sie auszugeben curl_setopt ($ ch, CURLOPT_RETURNTRANSFER, 1); $ output = curl_exec ($ ch); curl_close ($ ch); // gab es einen HTTP-Header für die Umleitung? if (preg_match ("! Location: (. *)!", $ output, $ passt)) echo "$ test_name: Weiterleitung zu $ match [1] \ n"; else echo "$ test_name: keine Umleitung \ n"; Echo "\ n \ n";
Zuerst müssen wir eine Reihe von URLs testen, gefolgt von einer Reihe von Browsereinstellungen, um jede dieser URLs zu testen. Dann durchlaufen wir diese Testfälle und stellen für jede eine cURL-Anfrage.
Aufgrund der Art und Weise, wie die cURL-Optionen eingerichtet werden, enthält die zurückgegebene Ausgabe nur die HTTP-Header (in $ output gespeichert). Mit einem einfachen Regex können wir sehen, ob ein Header "Location:" enthalten ist.
Wenn Sie dieses Skript ausführen, sollten Sie eine Ausgabe wie folgt erhalten:
Bei einer GET-Anfrage können Daten über die "Abfragezeichenfolge" an eine URL gesendet werden. Wenn Sie beispielsweise bei Google suchen, befindet sich der Suchbegriff im Abfragezeichenfolge-Teil der URL:
http://www.google.com/search?q=nettuts
Sie benötigen cURL möglicherweise nicht, um dies in einem Web-Skript zu simulieren. Sie können einfach nur faul sein und diese URL mit "file_get_contents ()" anklicken, um die Ergebnisse zu erhalten.
Einige HTML-Formulare sind jedoch auf die POST-Methode festgelegt. Wenn diese Formulare über den Browser übermittelt werden, werden die Daten nicht über die Abfragezeichenfolge, sondern über den HTTP-Anforderungshauptteil gesendet. Wenn Sie beispielsweise eine Suche in den CodeIgniter-Foren durchführen, POSTeten Sie Ihre Suchabfrage an:
http://codeigniter.com/forums/do_search/
Wir können ein PHP-Skript schreiben, um diese Art von URL-Anforderung zu simulieren. Zuerst erstellen wir eine einfache Datei zum Akzeptieren und Anzeigen der POST-Daten. Nennen wir es post_output.php:
print_r ($ _ POST);
Als Nächstes erstellen wir ein PHP-Skript, um eine cURL-Anforderung auszuführen:
$ url = "http: //localhost/post_output.php"; $ post_data = array ("foo" => "bar", "query" => "Nettuts", "action" => "Submit"); $ ch = curl_init (); curl_setopt ($ ch, CURLOPT_URL, $ url); curl_setopt ($ ch, CURLOPT_RETURNTRANSFER, 1); // wir machen eine POST-Anfrage curl_setopt ($ ch, CURLOPT_POST, 1); // Hinzufügen der Post-Variablen zur Anfrage curl_setopt ($ ch, CURLOPT_POSTFIELDS, $ post_data); $ output = curl_exec ($ ch); curl_close ($ ch); Echo $ -Ausgabe;
Wenn Sie dieses Skript ausführen, sollten Sie eine Ausgabe wie folgt erhalten:
Es hat einen POST an das post_output.php-Skript gesendet, das die Variable $ _POST ausgegeben hat, und wir haben diese Ausgabe über cURL erfasst.
Das Hochladen von Dateien funktioniert sehr ähnlich wie das vorherige POST-Beispiel, da für alle Dateiuploadformulare die POST-Methode verwendet wird.
Zuerst erstellen wir eine Datei für den Empfang der Anfrage und nennen sie upload_output.php:
print_r ($ _ FILES);
Und hier ist das eigentliche Skript zum Hochladen der Datei:
$ url = "http: //localhost/upload_output.php"; $ post_data = array ("foo" => "bar", // hochzuladende Datei "upload" => "@C: /wamp/www/test.zip"); $ ch = curl_init (); curl_setopt ($ ch, CURLOPT_URL, $ url); curl_setopt ($ ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt ($ ch, CURLOPT_POST, 1); curl_setopt ($ ch, CURLOPT_POSTFIELDS, $ post_data); $ output = curl_exec ($ ch); curl_close ($ ch); Echo $ -Ausgabe;
Wenn Sie eine Datei hochladen möchten, müssen Sie lediglich den Dateipfad wie eine post-Variable übergeben und das @ -Zeichen voranstellen. Wenn Sie dieses Skript ausführen, sollten Sie eine Ausgabe wie diese erhalten:
Eine der erweiterten Funktionen von cURL ist die Möglichkeit, ein "multi" cURL-Handle zu erstellen. Auf diese Weise können Sie Verbindungen zu mehreren URLs gleichzeitig und asynchron öffnen.
Bei einer regulären cURL-Anforderung wird die Skriptausführung angehalten und gewartet, bis die URL-Anforderung abgeschlossen ist, bevor sie fortgesetzt werden kann. Wenn Sie mehrere URLs treffen möchten, kann dies lange dauern, da Sie jeweils nur eine URL anfordern können. Wir können diese Einschränkung durch Verwendung des Multi-Handles überwinden.
Schauen wir uns diesen Beispielcode von php.net an:
// Erstelle beide cURL-Ressourcen $ ch1 = curl_init (); $ ch2 = curl_init (); // URL und andere geeignete Optionen setzen curl_setopt ($ ch1, CURLOPT_URL, "http://lxr.php.net/"); curl_setopt ($ ch1, CURLOPT_HEADER, 0); curl_setopt ($ ch2, CURLOPT_URL, "http://www.php.net/"); curl_setopt ($ ch2, CURLOPT_HEADER, 0); // das mehrfache cURL-Handle erstellen $ mh = curl_multi_init (); // füge die zwei Handles hinzu curl_multi_add_handle ($ mh, $ ch1); curl_multi_add_handle ($ mh, $ ch2); $ active = null; // die Handles ausführen do $ mrc = curl_multi_exec ($ mh, $ active); while ($ mrc == CURLM_CALL_MULTI_PERFORM); while ($ active && $ mrc == CURLM_OK) if (curl_multi_select ($ mh)! = -1) do $ mrc = curl_multi_exec ($ mh, $ active); while ($ mrc == CURLM_CALL_MULTI_PERFORM); // die Handles schließen curl_multi_remove_handle ($ mh, $ ch1); curl_multi_remove_handle ($ mh, $ ch2); curl_multi_close ($ mh);
Die Idee ist, dass Sie mehrere cURL-Handles öffnen und einem einzigen Multi-Handle zuweisen können. Dann können Sie warten, bis die Ausführung in einer Schleife abgeschlossen ist.
In diesem Beispiel gibt es zwei Hauptschleifen. Die erste do-while-Schleife ruft wiederholt curl_multi_exec () auf. Diese Funktion blockiert nicht. Es wird so wenig wie möglich ausgeführt und gibt einen Statuswert zurück. Solange der zurückgegebene Wert die Konstante 'CURLM_CALL_MULTI_PERFORM' ist, bedeutet dies, dass noch mehr Arbeit zu erledigen ist (z. B. das Senden von http-Headern an die URLs.).
In der folgenden while-Schleife machen wir so lange weiter, wie die $ active-Variable 'true' ist. Dies wurde als zweites Argument an den Aufruf curl_multi_exec () übergeben. Sie ist auf 'true' gesetzt, solange aktive Verbindungen mit dem Multi-Handle bestehen. Als nächstes rufen wir curl_multi_select () auf. Diese Funktion blockiert, bis eine Verbindungsaktivität vorliegt, z. B. eine Antwort. Wenn dies passiert, gehen wir in eine weitere Do-While-Schleife, um die Ausführung fortzusetzen.
Mal sehen, ob wir selbst ein Arbeitsbeispiel schaffen können, das einen praktischen Zweck hat.
Stellen Sie sich ein Blog mit vielen Beiträgen vor, die Links zu externen Websites enthalten. Einige dieser Links können aus verschiedenen Gründen nach einiger Zeit tot sein. Möglicherweise ist die Seite dort länger oder die gesamte Website ist verschwunden.
Wir werden ein Skript erstellen, das alle Links analysiert, nicht-ladende Websites und 404-Seiten findet und einen Bericht an uns zurücksendet.
Beachten Sie, dass dies kein wirkliches Wordpress-Plug-In sein wird. Es ist nur ein eigenständiges Hilfsskript und dient nur zu Demonstrationszwecken.
Also lasst uns anfangen. Zuerst müssen wir die Links aus der Datenbank abrufen:
// CONFIG $ db_host = 'localhost'; $ db_user = 'root'; $ db_pass = "; $ db_name = 'wordpress'; $ excluded_domains = array ('localhost', 'www.mydomain.com'); $ max_connections = 10; // einige Variablen initialisieren $ url_list = array (); $ working_urls = array (); $ dead_urls = array (); $ not_found_urls = array (); $ active = null; // Verbindung zu MySQL herstellen if (! mysql_connect ($ db_host, $ db_user, $ db_pass)) die ('Konnte keine Verbindung herstellen : '. mysql_error ()); if (! mysql_select_db ($ db_name)) die (' Konnte db nicht auswählen: '. mysql_error ()); // alle veröffentlichten Beiträge mit Links $ q = "SELECT post_content" abrufen FROM wp_posts WO post_content LIKE '% href =%' AND post_status = 'publish' AND post_type = 'post' "; $ r = mysql_query ($ q) oder die (mysql_error ()); while ($ d = mysql_fetch_assoc ($ r.) )) // Holen Sie sich alle Links über Regex, wenn (preg_match_all ("! href =" (. *?) \ "!", $ d ['post_content'], $ passend)) foreach ($ matches [1] als $ url) // einige Domänen ausschließen $ tmp = parse_url ($ url); if (in_array ($ tmp ['host'], $ excluded_domains)) continue; // Speichern Sie die URL $ url_list [] = $ url; // re Verschiebe Duplikate $ url_list = array_values (array_unique ($ url_list)); if (! $ url_list) die ('Keine zu überprüfende URL');
Zuerst haben wir eine Datenbankkonfiguration, gefolgt von einem Array von Domainnamen, die wir ignorieren werden ($ excluded_domains). Außerdem legen wir eine Anzahl für die maximale Anzahl gleichzeitiger Verbindungen fest, die wir später verwenden werden ($ max_connections). Dann stellen wir eine Verbindung zur Datenbank her, rufen Beiträge mit Links ab und sammeln sie in einem Array ($ url_list)..
Der folgende Code kann etwas komplex sein, daher werde ich versuchen, ihn in kleinen Schritten zu erklären.
// 1. multi handle $ mh = curl_multi_init (); // 2. Fügen Sie dem Multi-Handle mehrere URLs für ($ i = 0; $ i) hinzu < $max_connections; $i++) add_url_to_multi_handle($mh, $url_list); // 3. initial execution do $mrc = curl_multi_exec($mh, $active); while ($mrc == CURLM_CALL_MULTI_PERFORM); // 4. main loop while ($active && $mrc == CURLM_OK) // 5. there is activity if (curl_multi_select($mh) != -1) // 6. do work do $mrc = curl_multi_exec($mh, $active); while ($mrc == CURLM_CALL_MULTI_PERFORM); // 7. is there info? if ($mhinfo = curl_multi_info_read($mh)) // this means one of the requests were finished // 8. get the info on the curl handle $chinfo = curl_getinfo($mhinfo['handle']); // 9. dead link? if (!$chinfo['http_code']) $dead_urls []= $chinfo['url']; // 10. 404? else if ($chinfo['http_code'] == 404) $not_found_urls []= $chinfo['url']; // 11. working else $working_urls []= $chinfo['url']; // 12. remove the handle curl_multi_remove_handle($mh, $mhinfo['handle']); curl_close($mhinfo['handle']); // 13. add a new url and do work if (add_url_to_multi_handle($mh, $url_list)) do $mrc = curl_multi_exec($mh, $active); while ($mrc == CURLM_CALL_MULTI_PERFORM); // 14. finished curl_multi_close($mh); echo "==Dead URLs==\n"; echo implode("\n",$dead_urls) . "\n\n"; echo "==404 URLs==\n"; echo implode("\n",$not_found_urls) . "\n\n"; echo "==Working URLs==\n"; echo implode("\n",$working_urls); // 15. adds a url to the multi handle function add_url_to_multi_handle($mh, $url_list) static $index = 0; // if we have another url to get if ($url_list[$index]) // new curl handle $ch = curl_init(); // set the url curl_setopt($ch, CURLOPT_URL, $url_list[$index]); // to prevent the response from being outputted curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); // follow redirections curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1); // do not need the body. this saves bandwidth and time curl_setopt($ch, CURLOPT_NOBODY, 1); // add it to the multi handle curl_multi_add_handle($mh, $ch); // increment so next url is used next time $index++; return true; else // we are done adding new URLs return false;
Und hier ist die Erklärung für den obigen Code. Die Nummern in der Liste entsprechen den Nummern in den Codekommentaren.
Ich habe das Skript in meinem Blog ausgeführt (einige defekte Links wurden zu Testzwecken hinzugefügt), und so sah es aus:
Es dauerte nur weniger als 2 Sekunden, um etwa 40 URLs zu durchlaufen. Die Leistungssteigerungen sind erheblich, wenn Sie mit noch größeren URL-Gruppen arbeiten. Wenn Sie zehn Verbindungen gleichzeitig öffnen, kann sie zehnmal schneller ausgeführt werden. Sie können auch die nicht blockierenden Eigenschaften des Multi-Curl-Handles nutzen, um URL-Anforderungen auszuführen, ohne Ihr Webskript anzuhalten.
Wenn eine HTTP-basierte Authentifizierung für eine URL vorliegt, können Sie Folgendes verwenden:
$ url = "http://www.somesite.com/members/"; $ ch = curl_init (); curl_setopt ($ ch, CURLOPT_URL, $ url); curl_setopt ($ ch, CURLOPT_RETURNTRANSFER, 1); // Benutzername und Passwort senden curl_setopt ($ ch, CURLOPT_USERPWD, "myusername: mypassword"); // wenn Sie Weiterleitungen zulassen curl_setopt ($ ch, CURLOPT_FOLLOWLOCATION, 1); // Dadurch kann cURL weiterhin den Benutzernamen und das Kennwort senden //, nachdem er umgeleitet wurde curl_setopt ($ ch, CURLOPT_UNRESTRICTED_AUTH, 1); $ output = curl_exec ($ ch); curl_close ($ ch);
PHP hat eine FTP-Bibliothek, aber Sie können auch cURL verwenden:
// öffne einen Dateizeiger $ file = fopen ("/ path / to / file", "r"); // Die URL enthält die meisten benötigten Informationen. $ url = "ftp: // Benutzername: [email protected]: 21 / path / to / new / file"; $ ch = curl_init (); curl_setopt ($ ch, CURLOPT_URL, $ url); curl_setopt ($ ch, CURLOPT_RETURNTRANSFER, 1); // bezogene Optionen hochladen curl_setopt ($ ch, CURLOPT_UPLOAD, 1); curl_setopt ($ ch, CURLOPT_INFILE, $ fp); curl_setopt ($ ch, CURLOPT_INFILESIZE, Dateigröße ("/ Pfad / zur / Datei")); // für ASCII-Modus setzen (z. B. Textdateien) curl_setopt ($ ch, CURLOPT_FTPASCII, 1); $ output = curl_exec ($ ch); curl_close ($ ch);
Sie können Ihre URL-Anfrage über einen Proxy ausführen:
$ ch = curl_init (); curl_setopt ($ ch, CURLOPT_URL, 'http: //www.example.com'); curl_setopt ($ ch, CURLOPT_RETURNTRANSFER, 1); // Setze die Proxy-Adresse für die Verwendung von curl_setopt ($ ch, CURLOPT_PROXY, '11 .11.11.11: 8080 '); // wenn der Proxy einen Benutzernamen und ein Kennwort erfordert curl_setopt ($ ch, CURLOPT_PROXYUSERPWD, 'user: pass'); $ output = curl_exec ($ ch); curl_close ($ ch);
Es ist möglich, dass cURL während der URL-Anforderung bestimmte Callback-Funktionen abruft, bevor sie abgeschlossen ist. Wenn der Inhalt der Antwort heruntergeladen wird, können Sie beispielsweise die Daten verwenden, ohne auf den vollständigen Download zu warten.
$ ch = curl_init (); curl_setopt ($ ch, CURLOPT_URL, 'http: //net.tutsplus.com'); curl_setopt ($ ch, CURLOPT_WRITEFUNCTION, "progress_function"); curl_exec ($ ch); curl_close ($ ch); function progress_function ($ ch, $ str) echo $ str; return strlen ($ str);
Die Callback-Funktion MUSS die Länge der Zeichenfolge zurückgeben. Dies ist eine Voraussetzung dafür, dass dies ordnungsgemäß funktioniert.
Beim Abrufen der URL-Antwort wird bei jedem Empfang eines Datenpakets die Callback-Funktion aufgerufen.
Wir haben heute die Leistungsfähigkeit und Flexibilität der cURL-Bibliothek untersucht. Ich hoffe, Sie haben diesen Artikel genossen und gelernt. Wenn Sie das nächste Mal eine URL-Anforderung in Ihrer Webanwendung stellen müssen, sollten Sie cURL verwenden.
Vielen Dank und einen schönen Tag!
Wussten Sie, dass Sie bis zu 600 US-Dollar verdienen können, wenn Sie ein PLUS-Tutorial und / oder einen Screencast für uns schreiben? Wir suchen ausführliche und gut geschriebene Tutorials zu HTML, CSS, PHP und JavaScript. Wenn Sie die Möglichkeit haben, wenden Sie sich bitte an Jeffrey unter [email protected].
Bitte beachten Sie, dass die tatsächliche Kompensation von der Qualität des abschließenden Tutorials und des Screencasts abhängt.