I am really stuck in this, and need expert help. Let me explain what I am trying achieve and the setup. I had a script which posts over a https form using Zend_Http_Client. On the server setup I have tor & privoxy running. Everything just worked fine, but now I need to make the code more scalable by running multiple instances of tor & privoxy on the same server.
Hence I shifted the Adapter for Zend from Zend_Http_Client_Adapter_Curl to Zend_Http_Client_Adapter_Proxy . But after changing the adapter I have bumped into a strange error which says - 400 Invalid header received from client and when I dump the object of Zend client, I see the following -
MyWebClientResponse::__set_state(array(
'json' => NULL,
'version' => '1.1',
'code' => 400,
'message' => 'Invalid header received from client',
'headers' =>
array (
'Proxy-agent' => 'Privoxy 3.0.19',
'Content-type' => 'text/plain',
'Connection' => 'close',
),
'body' => 'Invalid header received from client.
',
))
I do not understand what is that I am doing wrong. The code is done in Yii Framework so it is hard to share all the classes and Models, but I am sharing the main parts of the code, which are responsible for this -
$client = MyWebClient::factory();
$adapter = $client->getAdapter();
$adapter->setConfig(array('timeout' => 120,
'proxy_host' => 'localhost',
'proxy_port' => 8124
));
$client->setAdapter($adapter);
$client->setCookieJar(true);
$client->setParameterPost(array(
'name' => 'firstname',
'password' => 'password,
'login' => 'home'
));
$response = $client->setUri('https://www.domain.com/post.php')->requestApi('POST', false);
Here's the constructor of the class MyWebClient, just in case it it required, all other methods are standard.
static public function factory($new = false)
{
if (!isset(self::$client))
{
self::$client = new MyWebClient();
self::$client->setConfig(array(
'adapter' => 'Zend_Http_Client_Adapter_Proxy',
// 'proxy_host' => 'localhost',
// 'proxy_port' => 8118,
'persistent' => false,
'timeout' => 120
));
}
return self::$client;
}
The headers are being set in the requestAPI method and the snippet is -
$headers = array(
'X-PHX' => 'true',
'X-Requested-With' => 'XMLHttpRequest',
'Referer' => 'https://domain.com/index.html',
'User-Agent' => self::getRandomUserAgent()
);
$this->setHeaders($headers);
I would really appreciate help in this regard. Think it's privoxy which is not letting go the request out of the server.
Sachin
Looks like you may need to wrap the user-agent with quotes. Try this when setting the headers and see if that fixes the problem.
$headers = array(
'X-PHX' => 'true',
'X-Requested-With' => 'XMLHttpRequest',
'Referer' => 'https://domain.com/index.html',
'User-Agent' => "'".self::getRandomUserAgent()."'"
);
$this->setHeaders($headers);
Finally I decided to use the native cURL library and the cookieJar which comes with it. It worked like expected.
Cheers,
Sachin
Related
I hope this question won't be marked as duplicate as I read many related questions and answers on the site: although I tried most of the suggestions out there I still couldn't resolve my problem.
My codebase : (I left comments on purpose to give an idea of what I have been trying so far, based on my browsing)
try {
$opts = array(
//~mrossw 'http' => array(
//~mrossw 'user_agent' => 'PHPSoapClient'
//~mrossw ),
//~mrossw 'socket' => array('bindto' => '158.69.189.149')
'socket' => array('bindto' => '127.0.0.1')
//~mrossw ,
//~mrossw 'ssl' => [
//~mrossw 'verify_peer' => true,
//~mrossw 'verify_peer_name' => true,
//~mrossw 'allow_self_signed' => true
//~mrossw ]
);
$context = stream_context_create($opts);
$client = new SoapClient("https://ws_provider_hostname:xxxx/foo/bar/blah/Operaciones/OpFooBarBlahReqABCS?wsdl",
//~mrossw $client = new SoapClient($doc_root.'OpCotizadorVehiculoExtReqABCS.xml',
array(
'location' => "https://ws_provider_hostname:xxxx/foo/bar/blah/Operaciones/OpFooBarBlahReqABCS?wsdl",
'uri' => "https://ws_provider_hostname:xxxx/foo/bar/blah/Operaciones",
// Stuff for development.
'trace' => 1,
'exceptions' => true,
'keep_alive' => true,
'connection_timeout' => 120,
'stream_context' => $context,
'cache_wsdl' => WSDL_CACHE_NONE,
'compression' => SOAP_COMPRESSION_ACCEPT | SOAP_COMPRESSION_GZIP | SOAP_COMPRESSION_DEFLATE,
//~mrossw 'local_cert' => $certRequest_param['sslcertfile'],
//~mrossw 'login'=>'username',
//~mrossw 'password' => 'password'
)
);
} catch (Exception $e) {
echo \"<h2>Exception Error!</h2>\";
echo $e->getMessage();
// print_r($e);
}
The WS provider has an dev environment on port xxxx and a prod env on port yyyy. Hostname and path request are the same.
SoapClient instanciation and operation call work perfect in dev env.
When i change the port to fetch against prod env I get the following error:
SOAP-ERROR: Parsing WSDL: Couldn't load from 'https://ws_provider_hostname:xxxx/foo/bar/blah/Operaciones/OpFooBarBlahReqABCS?wsdl' : failed to load external entity "https://ws_provider_hostname:xxxx/foo/bar/blah/Operaciones/OpFooBarBlahReqABCS?wsdl"
Provider says my public web server's IP is correctly set as allowed in their firewall. It looks right because when I tried to run the code from a different server with different IP and it fails with the same error in both dev and prod env.
When I run that code from a server inside a private network, it works in both
environment ! I don't know much about security, but this sounds to me like a security breach. I mention it here though, in case it can give a clue. I guess this is because this server has a private ip and the provider's firewall don't filter it.
When I go to https://ws_provider_hostname:xxxx/foo/bar/blah/Operaciones/OpFooBarBlahReqABCS?wsdl in my PC browser i get the correct wsdl's xml.
Do you have an idea of what can prevent the code to work form my public web server ?
Or maybe what else can I check ?
For example I couldn't find a way to check the ws server's http response code from outside my browser.
I could neither get a curl request form bash to return the wsdl xml, but that should be another question maybe.
Also let me know if i can provide any other relevant test or data.
Basically, I am trying to connect to a SOAP service with 2 way SSL (HTTP client certificate authentication).
I am using PHP SoapClient for this within Laravel.
This is what I have, and it allows me to connect and returns the expected response. So the method is basically correct and the certificate is fine etc. It's just I am having trouble with what I guess is the 2 way SSL part.
$client = new \SoapClient('localwsdlfile.wsdl', array(
'local_cert' => 'localcert.pem',
'passphrase' => 'passphrase',
// 'location' => 'https://wsmurl/login/' // Uncomment to login
));
$response = $client->Get(array(
"AccessKey" => "accesskey",
"ProductID" => "SOMEPRODUCT",
"Scope" => "SOMESCOPE",
"Parameters" => array('Param' => array('_' => 'DATATOLOOKUP', 'id'=>'MOREDATATOLOOKUP'))
));
print_r($response);
The only problem is (obviously because I'm doing something wrong), is I need to add the line 'location' => 'https://wsmurl/login/' the first time I try to connect, otherwise I get an error "SoapFault Login Required"
I then remove the line 'location' => 'https://wsmurl/login/', otherwise, I get an error "SoapFault looks like we got no XML document".
The service provider has a 600 second timeout, where I don't have to "login" again for upto 600 seconds.
After removing this line 'location' => 'https://wsmurl/login/', then it works as expected. Obviously, I can't manually add and remove this line, and I guess I am not doing this correctly.
Can someone tell me a better way to do this please?
Thanks,
Because the location for the login and localwsdlfile.wsdl is different, I could not do it with one call. So we created a function using curl to login and if login is successful it will proceed to the soapclient. Thanks to Brian from freelancer for his assistance here.
$client = new SoapClient('wsdl/VocusSchemas/localwsdlfile.wsdl', array(
'trace' => 1,
'exception' => true
));
try {
$response = $client->Get(array(
// "AccessKey" => "MADAITABNSAATOT1",
"AccessKey" => "accesskey",
"ProductID" => "SOMEPRODUCT",
"Scope" => "SOMESCOPE",
"Parameters" => array('Param' => array('_' => 'DATATOLOOKUP', 'id' => 'MOREDATATOLOOKUP'))
));
What I have till now
Right now I have a working oauth2 authentication between a laravel user and the dropbox API. Every user can upload files to their personal folder.
The Problem
After Uploading a file with laravel with the Dropbox API v2 I can see that there is a empty (0 Bytes) file uploaded.
Used to accomplish this task:
Laravel
Guzzle
Dropbox API Library
What am I missing?
The Code
My function for processing a form looks like this:
$formFile = $request->file('fileToUpload');
$path = $formFile->getClientOriginalName();
$file = $formFile->getPathName();
$result = Dropbox::files()->upload($path, $file);
return redirect('dropboxfiles');
And my files->upload function in my Dropbox Library looks like this:
$client = new Client;
$response = $client->post("https://content.dropboxapi.com/2/files/upload", [
'headers' => [
'Authorization' => 'Bearer '.$this->getAccessToken(),
'Content-Type' => 'application/octet-stream',
'Dropbox-API-Arg' => json_encode([
'path' => $path,
'mode' => 'add',
'autorename' => true,
'mute' => true,
'strict_conflict' => false
])
],
'data-binary' => '#'.$file
]);
The file, as I said, gets uploaded successfully. Correct name, but 0 Bytes. So empty file.
Thank you so much in advance for your help!
Update
With the following code I made it work. My question is though if there is a better "Laravel-Like" Solution instead of using fopen?
$response = $client->post("https://content.dropboxapi.com/2/files/upload", [
'headers' => [
'Authorization' => 'Bearer '.$this->getAccessToken(),
'Dropbox-API-Arg' => json_encode([
'path' => $path,
'mode' => 'add',
'autorename' => true,
'mute' => true,
'strict_conflict' => false
]),
'Content-Type' => 'application/octet-stream',
],
'body' => fopen($file, "r"),
]);
How #Greg mentioned (see cross-linking reference) I was able to solve this issue by using
'body' => fopen($file, "r"),
instead of
'data-binary' => '#'.$file
This is, how Greg mentioned, because data-binary is used in Curl requests. Other HTTP Clients, like Guzzle in my case use different names.
Im using zend_http_client and used code below to force traffic to fiddler :
$Http_Client = new Zend_Http_Client($Address);
$config = array(
'adapter' => 'Zend_Http_Client_Adapter_Proxy',
'proxy_host' => '127.0.0.1',
'proxy_port' => 8888,
'timeout' => 60,
'useragent' => 'Test',
'keepalive' => true,
'sslusecontext' => true
);
$Http_Client->setConfig($config);
when I run the program, I just get Http error 400 which means bad request.I searched a lot but found nothing helpful.In addition when I remove this config,everything works but fiddler does not capture any thing.
What can I do for this problem?
I'm having a recurring issue with PHP's inbuilt SOAP client where it returns the same error response regardless of the input paramaters.
Is there an advantage to using the SOAP library built into PHP or a disadvantage to directly querying via cURL through GET?
$client = new SoapClient("http://example.com/wdsl");
$params = array(
'Username' => 'username',
'Password' => 'pass',
'EventName' => 'Test Event',
'EventDate' => '2011-06-15T13:45:30',
'Destination' => '447987654321',
'Carrier' => '1',
'PhoneType' => '13',
'Originator' => 'ukflive',
'MessageText' => 'Test',
'LogoURL' => 'http://example.com/mail.gif',
'BookingReference' => '123456',
'Tickets' => '1',
'CollectionValidFrom' => '2011-06-15T13:45:30',
'CollectionValidTo' => '2011-06-15T18:45:30',
'TemplatePath' => '',
'PostBack' => 'http://example.com/'
);
$response = $client->__soapCall("SendManagedMobileTicket", $params);
print_r($response);
SoapClient is an integrated, actively maintained part of PHP5. cURL is the quick and dirty way to send HTTP data. The smart long term decision is to stick with SoapClient and its methods.
You may also want to look into the response headers, as shown in the notes section of the __soapCall() documentation page: http://www.php.net/manual/en/soapclient.soapcall.php#102387