i have been trying for the last several days to fetch a request from a website but no success.
I keep getting error 301.
Is anyone able to help me grab the content of this page: https://pre.corrupt-net.org/search.php?search=Lasse_Stefanz-Bara_Du-SE-CD-FLAC-1995-LoKET
I am looking forward to your reply.
EDIT:
This is the php function I've used:
function http_request(
$verb = 'GET', /* HTTP Request Method (GET and POST supported) */
$ip, /* Target IP/Hostname */
$port = 80, /* Target TCP port */
$uri = '/', /* Target URI */
$getdata = array(), /* HTTP GET Data ie. array('var1' => 'val1', 'var2' => 'val2') */
$postdata = array(), /* HTTP POST Data ie. array('var1' => 'val1', 'var2' => 'val2') */
$cookie = array(), /* HTTP Cookie Data ie. array('var1' => 'val1', 'var2' => 'val2') */
$custom_headers = array(), /* Custom HTTP headers ie. array('Referer: http://localhost/ */
$timeout = 1000, /* Socket timeout in milliseconds */
$req_hdr = false, /* Include HTTP request headers */
$res_hdr = false /* Include HTTP response headers */
)
{
$ret = '';
$verb = strtoupper($verb);
$cookie_str = '';
$getdata_str = count($getdata) ? '?' : '';
$postdata_str = '';
foreach ($getdata as $k => $v)
$getdata_str .= urlencode($k) .'='. urlencode($v);
foreach ($postdata as $k => $v)
$postdata_str .= urlencode($k) .'='. urlencode($v) .'&';
foreach ($cookie as $k => $v)
$cookie_str .= urlencode($k) .'='. urlencode($v) .'; ';
$crlf = "\r\n";
$req = $verb .' '. $uri . $getdata_str .' HTTP/1.1' . $crlf;
$req .= 'Host: '. $ip . $crlf;
$req .= 'User-Agent: Mozilla/5.0 Firefox/3.6.12' . $crlf;
$req .= 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8' . $crlf;
$req .= 'Accept-Language: en-us,en;q=0.5' . $crlf;
$req .= 'Accept-Encoding: deflate' . $crlf;
$req .= 'Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7' . $crlf;
foreach ($custom_headers as $k => $v)
$req .= $k .': '. $v . $crlf;
if (!empty($cookie_str))
$req .= 'Cookie: '. substr($cookie_str, 0, -2) . $crlf;
if ($verb == 'POST' && !empty($postdata_str)){
$postdata_str = substr($postdata_str, 0, -1);
$req .= 'Content-Type: application/x-www-form-urlencoded' . $crlf;
$req .= 'Content-Length: '. strlen($postdata_str) . $crlf . $crlf;
$req .= $postdata_str;
}
else $req .= $crlf;
if ($req_hdr)
$ret .= $req;
if (($fp = #fsockopen($ip, $port, $errno, $errstr)) == false)
return "Error $errno: $errstr\n";
stream_set_timeout($fp, 0, $timeout * 1000);
fputs($fp, $req);
while ($line = fgets($fp)) $ret .= $line;
fclose($fp);
if (!$res_hdr)
$ret = substr($ret, strpos($ret, "\r\n\r\n") + 4);
return $ret;
}
Firstly, 301 is not an "error" as such, it indicates that you are being redirected. You need to parse the response headers, take the value of the Location: header (which the HTTP protocol specification requires be present in a redirect response) and request that URI as well.
Secondly, the function above does not appear to provide any support for accessing HTTPS URLs. You need the OpenSSL extension installed for your PHP instance to do this, and you also need to actually call it some how. You could use the above function to do so by passing ssl:// or tls:// in front of the address in the $ip parameter, but you cannot simply pass the IP.
Thirdly, the usual way to do things like this is with the cURL extension. You would do something like this:
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'https://pre.corrupt-net.org/search.php?search=Lasse_Stefanz-Bara_Du-SE-CD-FLAC-1995-LoKET'); // Set the URL
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, TRUE); // Follow redirects
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE); // Get the result from the execution
if (($result = curl_exec($ch)) === FALSE) { // Execute the request
echo "cURL failed! Error: ".curl_error($ch);
} else {
echo "Success! Result: $result";
}
curl_close($ch);
Alternatively, if cURL is not available or you don't want to use it for some reason, you could have go with my HTTPRequest class, which is PHP4 compliant and requires no extensions (apart from OpenSSL for HTTPS requests). Documented(ish) in comments at the top of the script. You would do something like this:
$request = new httprequest(); // Create an object
// Set the request URL
if (!$request->setRequestURL('https://pre.corrupt-net.org/search.php?search=Lasse_Stefanz-Bara_Du-SE-CD-FLAC-1995-LoKET')) echo "Failed! Error: ".$request->getLastErrorStr()."<br>\r\n";
// Send the request
if (!$request->sendRequest()) echo "Failed! Error: ".$request->getLastErrorStr()."<br>\r\n";
echo "Success! Result: ".$request->getResponseBodyData(TRUE);
On a side note, a lot of the Scene PreDB managers/providers are not too keen on automated scraping, and you may get yourself banned...
Related
I have been trying to follow the steps laid out in the docs for twitter sign in here: https://dev.twitter.com/docs/auth/implementing-sign-twitter
My Code:
$oauth_consumer_secret = '***';
$access_token_secret = '***';
$oauth_consumer_key = '***';
$oauth_nonce = createNonce();
$oauth_signature_method = 'HMAC-SHA1';
$oauth_time = time();
$oauth_token = '***';
$oauth_version = '1.0';
$oauth = array(
'oauth_callback' => '***',
'oauth_consumer_key'=>$oauth_consumer_key,
'oauth_nonce'=>$oauth_nonce,
'oauth_signature_method'=>$oauth_signature_method,
'oauth_timestamp'=>$oauth_time,
'oauth_token'=>$oauth_token,
'oauth_version'=>$oauth_version
);
$baseURI = 'https://api.twitter.com/1.1/oauth/request_token';
$baseString = buildBaseString($baseURI,$oauth);
$compositeKey = getCompositeKey($oauth_consumer_secret,null);
$oauth_signature = base64_encode(hash_hmac('sha1', $baseString, $compositeKey, true));
$oauth['oauth_signature'] = $oauth_signature; //add the signature to our oauth array
$header = array(buildAuthorizationHeader($oauth));
$login = loginUser($baseURI,$header);
echo $login;
function loginUser($baseURI,$header){
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $baseURI);
curl_setopt($ch, CURLOPT_HEADER, TRUE);
curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 1);
$output = curl_exec($ch);
curl_close($ch);
if ($output!=''){
return $output;
} else {
return 'fail';
};
};
function buildBaseString($baseURI,$params){
$r = array(); // temp array
ksort($params); // sorts params alphabetically by key
foreach($params as $key=>$value){
$r[] = '$key='.rawurlencode($value);
};
return 'POST&'.rawurlencode($baseURI).'&'.rawurlencode(implode('&', $r)); // returns complete base string
};
// Create composite key
function getCompositeKey($consumerSecret,$requestToken){
return rawurlencode($consumerSecret) . '&' . rawurlencode($requestToken);
};
function createNonce(){
$characters = 'abcdefghijklmnopqrstuvwxyz0123456789';
$string = '';
for ($i=0; $i<32; $i++) {
$string .= $characters[rand(0, strlen($characters) - 1)];
};
return $string;
};
function buildAuthorizationHeader($oauth){
$r = 'Authorization: OAuth '; //header prefix
$values = array(); //temporary key=value array
foreach($oauth as $key=>$value)
$values[] = "$key=\"" . rawurlencode($value) . "\""; //encode key=value string
$r .= implode(', ', $values); //reassemble
return $r; //return full authorization header
};
The Problem I am having is that I am getting no response what so ever! So the login function just keeps returning 'fail'.
When I change curlopt_ssl_verifypeer to false I get a HTTP/1.1 401 Unauthorized error.
Any help or clues would be appreciated.
The SSL and OAuth issues are most likely separate.
As for SSL, your certificate authoririty (CA) bundle is most likely out of date. You can either tell curl to not verify the peer CURLOPT_SSL_VERIFYPEER = 0 or update the CA bundle. You can download a current CA bundle here. Most people (myself included) just turn off VERIFYPEER. Although this practice should be discouraged, it's a common solution.
When generating the request token, you do not need oauth_token in your oauth parameters. You are asking for a request token, you don't have one yet. Not sure if this matters, but only use ',' as the delimiter, not ', ' as in $r .= implode(', ', $values); //reassemble
I looked through the rest of your implementation and it looks right. Having written my own, I can appreciate the difficulty here.
I'm trying to create a fire and forget method in PHP so that I can POST data to a web server and not have wait for a response. I read that this could be achieved by using CURL like in the following code:
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $post_fields);
curl_exec($ch);
curl_close($ch);
However I don't think it works as I expect. For example if the URL I send the request to has an error it causes my script to throw an error as well. If it was fire and forget I would expect that not to happen.
Can anyone tell me whether I'm doing something wrong or offer an alternative suggestion. I'm using Windows locally and Linux for dev, staging and production environments.
UPDATE
I have found an alternative solution here: http://blog.markturansky.com/archives/205
I've cleaned it up into the code below:
function curl_post_async($url, $params = array())
{
// create POST string
$post_params = array();
foreach ($params as $key => &$val)
{
$post_params[] = $key . '=' . urlencode($val);
}
$post_string = implode('&', $post_params);
// get URL segments
$parts = parse_url($url);
// workout port and open socket
$port = isset($parts['port']) ? $parts['port'] : 80;
$fp = fsockopen($parts['host'], $port, $errno, $errstr, 30);
// create output string
$output = "POST " . $parts['path'] . " HTTP/1.1\r\n";
$output .= "Host: " . $parts['host'] . "\r\n";
$output .= "Content-Type: application/x-www-form-urlencoded\r\n";
$output .= "Content-Length: " . strlen($post_string) . "\r\n";
$output .= "Connection: Close\r\n\r\n";
$output .= isset($post_string) ? $post_string : '';
// send output to $url handle
fwrite($fp, $output);
fclose($fp);
}
This one seems to work better for me.
Is it a valid solution?
Yes, using sockets is the way to go if you don't care about the response from the URL you're calling. This is because socket connection can be terminated straight after sending the request without waiting and this is exactly what you're after - Fire and Forget.
Two notes though:
It's no longer a cURL request, so it's worth renaming the function. :)
It's definitely worth checking whether the socket could've been opened to prevent the script from complaining later when if fails:
$fp = fsockopen($parts['host'], $port, $errno, $errstr, 30);
if ( ! $fp)
{
return FALSE;
}
It's worth linking to the original source of the fsocket() script you're now using:
http://w-shadow.com/blog/2007/10/16/how-to-run-a-php-script-in-the-background/
Here is a cleaned up version of diggersworld's code that also handles other HTTP methods then POST and throws meaningful exceptions if the function fails.
/**
* Send a HTTP request, but do not wait for the response
*
* #param string $method The HTTP method
* #param string $url The url (including query string)
* #param array $params Added to the URL or request body depending on method
*/
public function sendRequest(string $method, string $url, array $params = []): void
{
$parts = parse_url($url);
if ($parts === false)
throw new Exception('Unable to parse URL');
$host = $parts['host'] ?? null;
$port = $parts['port'] ?? 80;
$path = $parts['path'] ?? '/';
$query = $parts['query'] ?? '';
parse_str($query, $queryParts);
if ($host === null)
throw new Exception('Unknown host');
$connection = fsockopen($host, $port, $errno, $errstr, 30);
if ($connection === false)
throw new Exception('Unable to connect to ' . $host);
$method = strtoupper($method);
if (!in_array($method, ['POST', 'PUT', 'PATCH'], true)) {
$queryParts = $params + $queryParts;
$params = [];
}
// Build request
$request = $method . ' ' . $path;
if ($queryParts) {
$request .= '?' . http_build_query($queryParts);
}
$request .= ' HTTP/1.1' . "\r\n";
$request .= 'Host: ' . $host . "\r\n";
$body = http_build_query($params);
if ($body) {
$request .= 'Content-Type: application/x-www-form-urlencoded' . "\r\n";
$request .= 'Content-Length: ' . strlen($body) . "\r\n";
}
$request .= 'Connection: Close' . "\r\n\r\n";
$request .= $body;
// Send request to server
fwrite($connection, $request);
fclose($connection);
}
I'm trying to figure out how to get this working with PHP. I have a working IPN for paypal that is less than 20 lines of code to get the data I need. I have tried reading the Google docs but they are either way too specific or way too general. There is some sample code, which is about 1300 lines in 5 files and I can't make sense of it. I just need a handful of vars back from a completed transaction, nothing more. Is it possible to do this with a few lines of code (and I mean without 1300 lines worth of "include" files) or is Google Checkout's process really that bulky?
Here's a bit of code I started. Not yet finished.
It works perfectly.
All you need to do is take the data Google sends back and this code writes to a file and use it to insert into your sales table send notification of payment received to customer and so on.
The trick is that when Google sends you a post you must call back with and Authorization header or it will not take it in consideration.
function post2google($url, $timeout = 30, $port = 80, $buffer = 128) {
$mid = "123456789";
$mky = "qwertyuiop";
$aut = base64_encode($mid . ":" . $mky);
$arr = parse_url($url);
$ssl = "";
if($arr['scheme'] == "https") $ssl = "ssl://";
$post = "POST " . $arr['path'] . " HTTP/1.1\r\n";
$post .= "Host: " . $arr['host'] . "\r\n";
$post .= "Authorization: Basic " . $aut . "\r\n";
$post .= "Content-Type: application/xml; charset=UTF-8\r\n";
$post .= "Accept: application/xml; charset=UTF-8\r\n";
$post .= "Content-Length: " . strlen($arr['query']) . "\r\n";
$post .= "Connection: Close\r\n";
$post .= "\r\n";
$post .= $arr['query'];
$f = fsockopen($ssl . $arr['host'], $port, $errno, $errstr, $timeout);
if(!$f)
return $errstr . " (" . $errno . ")";
else{
fputs($f, $post);
while(!feof($f)) { $echo .= #fgets($f, $buffer); }
fclose($f);
return $echo;
}
}
$re = post2google("https://checkout.google.com/api/checkout/v2/reportsForm/Merchant/123456789?_type=notification-history-request&serial-number=" . $_REQUEST['serial-number'], 3, 443);
$re = str_replace("&", "\n", $re) . "\n\n--\n\n";
file_put_contents("gpn.txt", $re, FILE_APPEND);
I've gotten it to work, and here's the skeleton of my code that can be used to handle HTTP notifications/responses. This was obviously derived from tntu's example above. (Thanks!)
//incoming data is in the var $_POST['serial-number']
//"send" the response to acknowledge the serial number that google talks about all over but never explains how
echo "_type=notification-acknowledgment&serial-number=".$_POST['serial-number'];
//now we need to call google's server and ask for this transaction's data:
//you'll need to change your merchant id in the $url and $mid vars, and your merchant key in the $mky var
$url = "https://sandbox.google.com/checkout/api/checkout/v2/reportsForm/Merchant/1234567890?_type=notification-history-request&serial-number=" . $_REQUEST['serial-number'];
$mid = "1234567890";
$mky = "ABCDEFGHIJK";
$aut = base64_encode($mid . ":" . $mky);
$arr = parse_url($url);
$ssl = "";
if($arr['scheme'] == "https") $ssl = "ssl://";
$post = "POST " . $arr['path'] . " HTTP/1.1\r\n";
$post .= "Host: " . $arr['host'] . "\r\n";
$post .= "Authorization: Basic " . $aut . "\r\n";
$post .= "Content-Type: application/xml; charset=UTF-8\r\n";
$post .= "Accept: application/xml; charset=UTF-8\r\n";
$post .= "Content-Length: " . strlen($arr['query']) . "\r\n";
$post .= "Connection: Close\r\n";
$post .= "\r\n";
$post .= $arr['query'];
//now we actually make the request by opening a socket and calling Google's server
$f = fsockopen($ssl . $arr['host'], 443, $errno, $errstr, 30);
if(!$f){
//something failed in the opening of the socket, we didn't contact google at all, you can do whatever you want here such as emailing yourself about it and what you were trying to send, etc
#mail("troubleshooting#yourdomain.com","Google IPN - HTTP ERROR ",$errstr . " (" . $errno . ")\n\n\n".$arr['query']);
}else{
//the socket was opened, send the request for the order data:
fputs($f, $post); // you're sending
while(!feof($f)) { $response .= #fgets($f, 128); } //google replies and you store it in $response
fclose($f); //close the socket, we're done talking to google's server
$spl=strpos($response,"_type="); //parse the type because parse_str won't catch it
if ($spl!==false){
$spl2=strpos($response,"&",$spl);
$ordertype=substr($response,($spl+6),($spl2-$spl)-6);
}//$ordertype will tell you which type of notification is being sent, new-order-notification, risk-information-notification, etc
$subresponse=substr($response,$spl2+1); //put the rest of it into an array for easy access
parse_str($subresponse,$order);//you can now access google's response in $order[] vars
//IMPORTANT: dots in Google's field names are replaced by underscore, for example:
// $order['google-order-number'] and $order['buyer-billing-address_address1'] NOT $order['buyer-billing-address.address1']
//order field names are shown here:
//https://developers.google.com/checkout/developer/Google_Checkout_HTML_API_Notification_API#order_summary
//this is the point where you will want to use the data contained in $order[] to create a new record in your database or whatever.
//NOTE: be sure to store and check for duplicates using the google-order-number because you will get multiple notifications from google regarding the same order
if (strtoupper($order['order-summary_financial-order-state']) == "CHARGEABLE"){
//CHARGEABLE is what indicates it is safe to create a login for the user (if you are delivering digital goods)
// insert into db, and/or email user with key or download url
}
}
I am trying to implement Paypal IPN but it never reaches the url I've set. I've written a script to log visits to this url and all I get are my visits.
How long does it take for Paypal to sent the notification?
EDIT
IPNs suddenly started to come but now I can't verify...Here is the code:
$url = 'https://www.paypal.com/cgi-bin/webscr';
$postdata = '';
foreach ($_POST as $i => $v) {
$postdata .= $i . '=' . urlencode($v) . '&';
}
$postdata .= 'cmd=_notify-validate';
$web = parse_url($url);
if ($web['scheme'] == 'https') {
$web['port'] = 443;
$ssl = 'ssl://';
} else {
$web['port'] = 80;
$ssl = '';
}
$fp = #fsockopen($ssl . $web['host'], $web['port'], $errnum, $errstr, 30);
if (!$fp) {
echo $errnum . ': ' . $errstr;
} else {
fputs($fp, "POST " . $web['path'] . " HTTP/1.1\r\n");
fputs($fp, "Host: " . $web['host'] . "\r\n");
fputs($fp, "Content-type: application/x-www-form-urlencoded\r\n");
fputs($fp, "Content-length: " . strlen($postdata) . "\r\n");
fputs($fp, "Connection: close\r\n\r\n");
fputs($fp, $postdata . "\r\n\r\n");
while (!feof($fp)) {
$info[] = #fgets($fp, 1024);
}
fclose($fp);
$info = implode(',', $info);
if (eregi('VERIFIED', $info)) {
} else {
}
}
I already commented above. But I'm pretty sure the html encoded & is messing up your callback.
There's big difference between URL encoding and HTML encoding.
Change this '&' to this '&'. & is a url/post character used to separate different sets of key/value pairs. By changing it to &, you made your whole callback a single value.
Also, just some advice, but I would ditch this
if (eregi('VERIFIED', $info)) {} else {}
and replace it with this
if (preg_match('/VERIFIED/', $info)) {} else {}
eregi is depreciated.
http://php.net/manual/en/function.eregi.php
I have spent the past couple of hours trying all types of variations but according to the Twitter API this should have worked from step 1!
1 addition I have made to the script below is that I have added in:
$header = array("Expect:");
This I found helped in another question on stackoverflow from getting a denied issue / 100-continue.
Issue:
Failed to validate oauth signature and token is the response EVERY time!!!
Example of my post data:
Array ( [oauth_callback] => http://www.mysite.com//index.php [oauth_consumer_key] => hidden [oauth_nonce] => hidden [oauth_signature_method] => HMAC-SHA1 [oauth_timestamp] => 1301270847 [oauth_version] => 1.0 )
And my header data:
Array ( [0] => Expect: )
Script:
$consumer_key = "hidden";
$consumer_secret = "hidden";
function Post_Data($url,$data,$header){
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS,$data);
curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$result = curl_exec($ch);
curl_close($ch);
return $result;
}
$data['oauth_callback'] = "http://".$_SERVER['HTTP_HOST'].$_SERVER['PHP_SELF'];
$data['oauth_consumer_key'] = $consumer_key;
$data['oauth_nonce'] = md5(time());
$data['oauth_signature_method'] = "HMAC-SHA1";
$data['oauth_timestamp'] = time();
$data['oauth_version'] = "1.0";
$header = array("Expect:");
$content = Post_Data("http://api.twitter.com/oauth/request_token",$data,$header);
print_r($content);
Can anybody see an obvious mistake that I may be making here? Preferably I would not like to go with somebody elses code as most examples have full classes & massive functions, I am looking for the most simple approach!
Your problem is that you did not include the OAuth signature in your request.
You can read about the concept on this page.
A working implementation can be found here.
I faced same issue, what I was missing is passing header in to the curl request.
As shown in this question, I was also sending the $header = array('Expect:'), which was the problem in my case. I started sending signature in header with other data as below and it solved the case for me.
$header = calculateHeader($parameters, 'https://api.twitter.com/oauth/request_token');
function calculateHeader(array $parameters, $url)
{
// redefine
$url = (string) $url;
// divide into parts
$parts = parse_url($url);
// init var
$chunks = array();
// process queries
foreach($parameters as $key => $value) $chunks[] = str_replace('%25', '%', urlencode_rfc3986($key) . '="' . urlencode_rfc3986($value) . '"');
// build return
$return = 'Authorization: OAuth realm="' . $parts['scheme'] . '://' . $parts['host'] . $parts['path'] . '", ';
$return .= implode(',', $chunks);
// prepend name and OAuth part
return $return;
}
function urlencode_rfc3986($value)
{
if(is_array($value)) return array_map('urlencode_rfc3986', $value);
else
{
$search = array('+', ' ', '%7E', '%');
$replace = array('%20', '%20', '~', '%25');
return str_replace($search, $replace, urlencode($value));
}
}