I have a cURL command like this:
curl 'https://www.example.com' \
-H 'user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.70 Safari/537.36' \
-H 'accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3' \
-H 'accept-language: de-DE,de;q=0.9,en-US;q=0.8,en;q=0.7' \
-H 'authority: www.example.com'
Executing this in a command line like in Terminal app on my Mac, results to the expected output.
(In case you test it yourself: If this output contains the word Sicherheitsüberprüfung it's geo blocked and you have to use a German IP to test it.)
I transferred the exact command to PHP cURL like this:
<?php
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'https://www.example.com');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'GET');
$headers = array();
$headers[] = 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.70 Safari/537.36';
$headers[] = 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3';
$headers[] = 'Accept-Language: de-DE,de;q=0.9,en-US;q=0.8,en;q=0.7';
$headers[] = 'Authority: www.example.com';
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
$result = curl_exec($ch);
curl_close($ch);
echo $result;
?>
When I run this code I'm getting a message that my request was recognized as automated request/robot: It says Sicherheitsüberprüfung, means security check.
Of course, I'm using the same IP for both, command line and PHP cURL request.
Why that? Isn't command line cURL the same as PHP cURL?
Or is there anything wrong with my PHP script?
UPDATE
I fortuitously found out the following: I'm using Coda as code editor on my Mac. This has a build-in PHP rendering engine. Using this with my PHP script, the result is as expected. It's the same result I'm getting in the command line.
UPDATE 2
I made what Jannes Botis suggested in his answer. I then ran the PHP script in my Coda code editor app (what output the expected) and with MAMP as localhost (what is always recognized as automated request).
I figured out that the the code executed with MAMP was using HTTP/2 while the code executed in Coda is using HTTP/1.1. To solve this, I added the following to the script:
curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
Now, both output exact the same string:
GET / HTTP/1.1
Host: www.example.com
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.70 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3
Accept-Language: de-DE,de;q=0.9,en-US;q=0.8,en;q=0.7
Authority: www.example.com
But, it's still the same: The one is working, the other is recognized as automated request.
Try to debug the request in both cases:
a) Terminal: use curl verbose mode: curl -v and check the http request sent, especially check the header list
b) php curl: print the http request using CURLINFO_HEADER_OUT:
curl_setopt($ch, CURLINFO_HEADER_OUT, true);
curl_exec($ch);
$info = curl_getinfo($ch);
print_r($info['request_header']);
Testing the different headers, what made it work was adding "Pragma: no-cache" header to the request:
$headers[] = 'Pragma: no-cache';
On the other hand, in terminal curl, I had to uppercase the request headers, e.g. User-Agent etc.
Try to create a tcp connection with fsockopen:
$fp = fsockopen("ssl://"."www.example.com", 443, $errno, $errstr, 30);
if (!$fp) {
echo "$errstr ($errno)<br />\n";
} else {
$out = "GET / HTTP/1.1\r\n";
$out .= "Host: www.example.com\r\n";
$headers = array();
$headers[] = 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.70 Safari/537.36';
$headers[] = 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3';
$headers[] = 'Accept-Language: de-DE,de;q=0.9,en-US;q=0.8,en;q=0.7';
$headers[] = 'Authority: www.example.com';
$out .= $headers;
$out .= "Connection: Close\r\n\r\n";
fwrite($fp, $out);
while (!feof($fp)) {
echo fgets($fp, 1024);
}
fclose($fp);
and test if this works. Maybe the issue is either that php curl adds some info to the http request or the problem is on the tcp connection level, some info added there.
References
cURL works from Terminal, but not from PHP
PHP cURL: modify/overwrite Connection header
Sending TCP Data with PHP
Command line curl :
It is a tool to transfer data to or from a server, using any of the supported protocols (HTTP, FTP, IMAP, POP3, SCP, SFTP, SMTP, TFTP, TELNET, LDAP or FILE). curl is powered by Libcurl. This tool is preferred for automation, since it is designed to work without user interaction. curl can transfer multiple file at once.
For more details for Command line curl
Syntax:
curl [options] [URL...]
Example:
curl http://site.{one, two, three}.com
PHP cURL
$ch = curl_init('http://example.com/wp-login.php');
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 3);
if($this->getRequestType() == 'POST')
{
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS,
array(
'user[name]' => 'Generic+Username',
'user[email]' => 'mahekpatel04#gmail.com'
);
);
}
$response = curl_exec($ch);
The issue is with ciphers selected by PHP's cURL by default.
Running curl command with -Ivs options allows us to see what ciphers it uses:
* Cipher selection: ALL:!EXPORT:!EXPORT40:!EXPORT56:!aNULL:!LOW:!RC4:#STRENGTH
Setting them in PHP allows it to bypass this mysterious check:
curl_setopt($ch,
CURLOPT_SSL_CIPHER_LIST,
'ALL:!EXPORT:!EXPORT40:!EXPORT56:!aNULL:!LOW:!RC4:#STRENGTH'
);
Also, it seems that Host header and using HTTPv2 should be added:
$headers[] = 'Host: www.11880.com';
// ...
curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2_0);
Related
Hello everyone I have this CURL that works if I put the "wp_create_nonce" cookie user manually.
And when I execute the php from my browser with the user logged in.
The problem is to get the "wp_create_nonce" of the user from the cookies, is there any way to get it or simulate it?
The problem is when I run the php from the Cron it doesn't take the current session from the CURL to create the wp_create_nonce
Code CURL PHP
//We get wp_create_nonce from the current user logged
//$fb_product_id = 27540 is the ID of the product.
$nemo = wp_create_nonce( 'update-post_'.$fb_product_id);
$nemowoo = wp_create_nonce( 'woocommerce_save_data', 'woocommerce_meta_nonce' );
//Start CURL
$chanelfacebook = curl_init();
curl_setopt($chanelfacebook, CURLOPT_URL, 'https://myserverexample.com/wp-admin/post.php');
curl_setopt($chanelfacebook, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($chanelfacebook, CURLOPT_POST, 1);
curl_setopt($chanelfacebook, CURLOPT_POSTFIELDS, "_wpnonce=".$nemo."&user_ID=1&action=editpost&post_ID=".$fb_product_id."&woocommerce_meta_nonce=".$nemowoo."&_wc_pre_orders_enabled=yes&facebookpreloadedu=yes&save=Actualizar");
curl_setopt($chanelfacebook, CURLOPT_ENCODING, 'gzip, deflate');
$headersfacebook = array();
$headersfacebook[] = 'Authority: miserverexample.com';
$headersfacebook[] = 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9';
$headersfacebook[] = 'Accept-Language: es-419,es;q=0.9,en;q=0.8';
$headersfacebook[] = 'Cache-Control: max-age=0';
$headersfacebook[] = 'Content-Type: application/x-www-form-urlencoded';
$headersfacebook[] = 'Cookie: //cookie deleted for security//';
$headersfacebook[] = 'Origin: https://myserverexample.com';
$headersfacebook[] = 'Referer: https://myserverexample.com/wp-admin/post.php?post='.$fb_product_id.'&action=edit';
$headersfacebook[] = 'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36';
curl_setopt($chanelfacebook, CURLOPT_HTTPHEADER, $headersfacebook);
$result = curl_exec($chanelfacebook);
if (curl_errno($chanelfacebook)) { error_log( print_r( "Error de Curl EN STOCK: ".curl_error($chanelfacebook), true ) ); }
curl_close($chanelfacebook);
The problem is creating the wp_create_nonce by doing it manually in the cron from the browser where the user is logged in works.
But if it is done from the cron when there is no user, it does not work.
How to solve it?
I can think of maybe an impersonate user to generate the code "wp_create_nonce"
P.D:
1.- I am doing CURL to the same origin server.
2.- CURL works fine if I run it from the browser where the curl cookie user is logged in.
In short I need to simulate the "wp_create_nonce" by user_id is this possible?
Example:
wp_create_nonce( 'update-post_'.$fb_product_id, $simulateiduser);
I'm trying to use CURL to assess the visitors on my site. I'd like to see if they are being linked from a bad neighborhood or not. Most of the time my current code works, but not always.
I'm having a bit of trouble making my CURL able to fool all servers. How do I make my CURL headers totally convincing, and remove any possible clues that I'm using CURL?
<?php
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL,"http://www.example.com");
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS,$vars); //Post Fields
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$headers = array();
$headers[] = 'X-Apple-Tz: 0';
$headers[] = 'X-Apple-Store-Front: 143444,12';
$headers[] = 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8';
$headers[] = 'Accept-Encoding: gzip, deflate';
$headers[] = 'Accept-Language: en-US,en;q=0.5';
$headers[] = 'Cache-Control: no-cache';
$headers[] = 'Content-Type: application/x-www-form-urlencoded; charset=utf-8';
$headers[] = 'Host: www.example.com';
$headers[] = 'Referer: http://www.example.com/index.php'; //Your referrer address
$headers[] = 'User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux i686; rv:28.0) Gecko/20100101 Firefox/28.0';
$headers[] = 'X-MicrosoftAjax: Delta=true';
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
$server_output = curl_exec ($ch);
print $server_output;
curl_close ($ch);
if (strpos($output,'sex') !== false)
{
echo 'sex';
}
?>
For example, a certain well known adult video site with an orange logo that looks a lot like the YouTube logo (maybe you guys know the one) responded with this:
403 Forbidden
Request forbidden by administrative rules.
__SERVERNAME__
In chrome dev tools, you can obtain the full HTTP request chrome used against a URL by:
opening dev tools
goto the "network" tab
request the URL you want - if you are already on the target page - hit F5 or reload.
Dev tools will then generate a list of HTTP requests (and responses) made
right click on the HTTP request / URL you are interested in
click the "save as curl" option and you will now have the full HTTP request details (for command line curl ) in your clipboard.
By using these values when sending an HTTP request your request will ostensibly appear to be made by a Chrome web browser.
A server I am working on appears to be denying outbound HTTP requests. The reason I think this is because I've tried both Guzzle and curl requests to the API.
The API lives on the same domain as the web server (this is temporary at clients request). I can make requests to the API server via Postman (Chrome plugin), but when I run that same request on the server, it doesn't return anything.
Here are the headers from the 'Postman' request:
POST /api2/user/session HTTP/1.1
Host: example.com
Connection: keep-alive
Content-Length: 49
Cache-Control: no-cache
Origin: chrome-extension://fdmmgilgnpjigdojojpjoooidkmcomcm
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.76 Safari/537.36
Content-Type: application/x-www-form-urlencoded
Accept: */*
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.8
Cookie: PHPSESSID=d9ad79c4c0822fc5c86f4d8799307f1b; _ga=GA1.2.1674422587.1425409444
Post data:
token=a559d5bba5a9e9517d5c3ed7aeb62db6&user=30972
This works. It returns the data. But when I call the same endpoint from within my web app, I get nothing.
$data = urlencode("token=a559d5bba5a9e9517d5c3ed7aeb62db6&user=30972");
$ch = curl_init('http://example.com/api2/user/session');
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'Content-Type: application/x-www-form-urlencoded',
'Content-Length: ' . strlen($data))
);
$result = curl_exec($ch);
What I don't understand is I can run the following, and it returns the content:
print file_get_contents("http://www.google.com");
When I var_dump the $_POST fields on the endpoint user/session it returns the array of postdata using Postman but $_POST fields are blank when sending via the web app. Even before it makes any request to the database, the post fields should be set right?
Via SSH this also works:
curl -F token=a559d5bba5a9e9517d5c3ed7aeb62db6 -F user=30972 http://example.com/api2/user/session
As suggested in comments I've tried:
var_dump(function_exists('curl_version'));
// bool(true)
I can't figure out what's going on.
Edit: This works ... but I don't want to use sockets. Must be a curl issue.
$fp = fsockopen('example.com', 80);
$vars = array(
'token' => 'a559d5bba5a9e9517d5c3ed7aeb62db6',
'user' => '30972'
);
$content = http_build_query($vars);
fwrite($fp, "POST /api2/user/session HTTP/1.1\r\n");
fwrite($fp, "Host: example.com\r\n");
fwrite($fp, "Content-Type: application/x-www-form-urlencoded\r\n");
fwrite($fp, "Content-Length: ".strlen($content)."\r\n");
fwrite($fp, "Connection: close\r\n");
fwrite($fp, "\r\n");
fwrite($fp, $content);
header('Content-type: text/plain');
while (!feof($fp)) {
echo fgets($fp, 1024);
}
Edit:
curl_error() also returns no error.
To better understand the differences between the PHP code and cURL, I created a RequestBin instance and tried both on it. They yielded drastically different results:
It seemed like the POST data from the PHP script yielded an incorrect result for what was sent. This can be fixed by using a built-in PHP function http_build_query.
It will yield a more apt result:
This can be caused by a session lock... If you use curl to access the same server, the same session is used. While the script is running, the session is locked by default, this means that the current request has to finish before another is handled for the same session. This would explain a timeout of the request in curl, as your first request is not completed and another is made...
Using session_write_close() before the curl_exec will unlock the session and correct the problem.
It turns out I needed to use http_build_query.
$vars = array(
'token' => 'a559d5bba5a9e9517d5c3ed7aeb62db6',
'user' => '30972'
);
$content = http_build_query($vars);
$ch = curl_init('http://example.com/api2/user/session');
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'Content-Type: application/x-www-form-urlencoded',
'Content-Length: ' . strlen($content))
);
$result = curl_exec($ch);
I'm making request to LinkedIn page and receiving "HTTP/1.1 999 Request denied" response.
I use AWS/EC-2 and get this response.
On localhost everything works fine.
This is sample of my code to get html-code of the page.
<?php
error_reporting(E_ALL);
$url= 'https://www.linkedin.com/pulse/5-essential-strategies-digital-michelle';
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HEADER, true);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
$response = curl_exec($ch);
$info = curl_getinfo($ch);
curl_close($ch);
var_dump($response);
var_dump($info);
I don't need whole page content, just meta-tags (title, og-tags).
Note that the error 999 don't exist in W3C Hypertext Transfer Protocol - HTTP/1.1, probably this error is customized (sounds like a joke)
LinkedIn don't allow direct access, the probable reason of them blocking any "url" from others webservers access should be to:
Prevent unauthorized copying of information
Prevent invasions
Prevent abuse of requests.
Force use API
Some IP addresses of servers are blocked, as the "IP" from "domestic ISP" are not blocked and that when you access the LinkedIn with web-browser you use the IP of your internet provider.
The only way to access the data is to use their APIs. See:
Accessing LinkedIn public pages using Python
Heroku requests return 999
Note: The search engines like Google and Bing probably have their IPs in a "whitelist".
<?php
header("Content-Type: text/plain");
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "https://www.linkedin.com/company/technistone-a-s-");
$header = array();
$header[] = "Host: www.linkedin.com";
$header[] = "User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:50.0) Gecko/20100101 Firefox/50.0";
$header[] = "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8";
$header[] = "Accept-Language: en-US,en;q=0.5";
$header[] = "Accept-Encoding: gzip, deflate, br";
$header[] = "Connection: keep-alive";
$header[] = "Upgrade-Insecure-Requests: 1";
curl_setopt($ch,CURLOPT_ENCODING , "gzip");
curl_setopt($ch, CURLOPT_HTTPHEADER , $header);
$my_var = curl_exec($ch);
echo $my_var;
LinkedIn is not supporting the default encoding 'identity' , so if you set the header
'Accept-Encoding': 'gzip, deflate'
you should get the response , but you would have to decompress it.
I ran into this while doing local web development and using the LinkedIn badge feature (profile.js). I was only getting the 999 Request denied in Chrome, so I just cleared my browser cache and localStorage and it started to work again.
UPDATE - Clearing cache was just a coincidence and the issue came back. LinkedIn is having issues with their badge functionality.
I submitted a help thread to their forums.
https://www.linkedin.com/help/linkedin/forum/question/714971
When i am trying to get the website content from the external url fanpop.com by using file_get_contents in php, i am getting empty data. I used the below code to get the contents
$add_url= "http://www.fanpop.com/";
$add_domain = file_get_contents($add_url);
echo $add_domain;
but here i am getting empty result for $add_domain. But the same code is working for other urls and i tried to send the request from browser not from the script then also it is not working.
Below is the same request, but in CURL:
error_reporting(-1);
ini_set('display_errors','On');
$url="http://www.fanpop.com/";
$ch = curl_init();
$header=array('GET /1575051 HTTP/1.1',
'Host: adfoc.us',
'Accept:text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'Accept-Language:en-US,en;q=0.8',
'Cache-Control:max-age=0',
'Connection:keep-alive',
'Host:adfoc.us',
'User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.116 Safari/537.36',
);
curl_setopt($ch,CURLOPT_URL,$url);
curl_setopt($ch,CURLOPT_RETURNTRANSFER,true);
curl_setopt($ch,CURLOPT_CONNECTTIMEOUT,0);
curl_setopt( $ch, CURLOPT_COOKIESESSION, true );
curl_setopt($ch,CURLOPT_COOKIEFILE,'cookies.txt');
curl_setopt($ch,CURLOPT_COOKIEJAR,'cookies.txt');
curl_setopt($ch,CURLOPT_HTTPHEADER,$header);
echo $result=curl_exec($ch);
curl_close($ch);
... but the above is also not working, can any one tell is there any any changes have to make in that?
The problem with this particular site is that it only serves compressed contents and throws a 404 error otherwise.
Easy fix:
$ch = curl_init('http://www.fanpop.com');
curl_setopt($ch,CURLOPT_ENCODING , "");
curl_exec($ch);
You can also make this work for file_get_contents() but with a substantial amount of effort, as described in this article.