Strange file_get_contents behavior from same server - http-status-code-404

This issue is a bit strange. I have a URL that opens well in any browser.
I can get the contents of this URL using file_get_contents() function from my local server or any other server, but when I run the page with file_get_contents() function on the same server, it gives 404 error.
file_get_contents() is enabled on this server because it can read content of URLs hosted on other servers.
Let me explain a bit more in detail.
In need to read URL1 on my web server from URL2 on the same server.
URL1 can be read from any other server but not from the URL2 as both URLs are on the same server.
I guess it has to do something with server settings.
Thank you!

You may wanna try CURL instead of file_get_contents() :
function get_web_page( $url )
{
$options = array(
CURLOPT_RETURNTRANSFER => true, // return web page
CURLOPT_HEADER => false, // don't return headers
CURLOPT_FOLLOWLOCATION => true, // follow redirects
CURLOPT_ENCODING => "", // handle all encodings
CURLOPT_USERAGENT => "spider", // who am i
CURLOPT_AUTOREFERER => true, // set referer on redirect
CURLOPT_CONNECTTIMEOUT => 120, // timeout on connect
CURLOPT_TIMEOUT => 120, // timeout on response
CURLOPT_MAXREDIRS => 10, // stop after 10 redirects
);
$ch = curl_init( $url );
curl_setopt_array( $ch, $options );
$content = curl_exec( $ch );
$err = curl_errno( $ch );
$errmsg = curl_error( $ch );
$header = curl_getinfo( $ch );
curl_close( $ch );
$header['errno'] = $err;
$header['errmsg'] = $errmsg;
$header['content'] = $content;
return $header;
}
$x=get_web_page('http://yourserver/the_script.php');
echo $x["content"];

Related

drupal_mail() returns true but unable to send mail

I have written a drupal module with custom form api which will send email to my inbox on each submit. I have written a condition under drupal_mail which returns true but shows an error message "Unable to send e-mail. Contact the site administrator if the problem persists."
Below my code:
function my_module_name_mail($key, &$message, $params)
{
$headers = array(
'MIME-Version' => '1.0',
'Content-Type' => 'text/html; charset=UTF-8;',
'Content-Transfer-Encoding' => '8Bit',
'X-Mailer' => 'Drupal'
);
foreach ($headers as $key => $value) {
$message['headers'][$key] = $value;
}
$message['subject'] = $params['subject'];
$message['body'] = $params['body'];
}
function my_module_name_form_submit($form, &$form_state)
{
$from = $form_state['values']['email'];
$body= 'Name: '.$name.'<br />Email: '.$email;
$to = "my_mail_id#example.com";
$params = array(
'body' => $body,
'subject' => 'Website Information Request',
);
drupal_mail('my_module_name', 'some_mail_key', $to, language_default(), $params, $from, TRUE);
}
Check your Drupal logs for more clues. Enable devel / devel-admin modules. Once you do, drupal_mail will pipe emails to your temp directory, which will help you narrow down if the problem is with your email server or the config.

Not Getting access token from of Gmail Contacts API using Oauth2 while code is in Google App Engine Server

I am using zend-framework2 and google-app-engine server to import all gmail contact list. I am getting authorization code from gmail after login. When hitting curl using this authorization code to get access token, it gives blank array as response.
Also this app is a billed app in google-app-engine. and already set
extension = "curl.so"
in php.ini file. and the credentials which i have given are correct.
// Import Gmail Contacts
$client_id='xxxxxxxxxxxxxxxxxxxxxxxxxxxx.apps.googleusercontent.com';
$client_secret='xxxxxxxxxxxxxx-xxxxxxxxx';
$redirect_uri='http://xxxxxxxxxxxxxxx.appspot.com/u/invite/gmailCallback';
$max_results = 1000;
if(isset($_GET["code"]) && $_GET["code"] != '') {
$auth_code = $_GET["code"];
$fields=array(
'code'=> urlencode($auth_code),
'client_id'=> urlencode($client_id),
'client_secret'=> urlencode($client_secret),
'redirect_uri'=> urlencode($redirect_uri),
'grant_type'=> urlencode('authorization_code')
);
$post = '';
foreach($fields as $key=>$value) { $post .= $key.'='.$value.'&'; }
$post = rtrim($post,'&');
$curl = curl_init();
curl_setopt($curl,CURLOPT_URL,'https://accounts.google.com/o/oauth2/token');
curl_setopt($curl,CURLOPT_POST,5);
curl_setopt($curl,CURLOPT_POSTFIELDS,$post);
curl_setopt($curl, CURLOPT_RETURNTRANSFER,TRUE);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER,FALSE);
$result = curl_exec($curl);
//$info = curl_getinfo($curl);
//echo "<pre>"; print_r($info); die;
curl_close($curl);
$response = json_decode($result);
//echo "<pre>"; var_dump($response); die;
if(isset($response->access_token) && $response->access_token != '') {
$accesstoken = $response->access_token;
$url = 'https://www.google.com/m8/feeds/contacts/default/full?max-results='.$max_results.'&oauth_token='.$accesstoken;
//$url = 'https://www.google.com/m8/feeds/contacts/default/full?oauth_token='.$accesstoken;
$xmlresponse = $this->curl_file_get_contents($url);
//At times you get Authorization error from Google.
if((strlen(stristr($xmlresponse,'Authorization required'))>0) && (strlen(stristr($xmlresponse,'Error '))>0)) {
//$returnArr['error_msg'] = "Something went wrong to import contacts!!";
echo '<h2>Something went wrong to import contacts !!</h2>';die;
} else {
$xml = new SimpleXMLElement($xmlresponse);
$xml->registerXPathNamespace('gd', 'http://schemas.google.com/g/2005');
$result = $xml->xpath('//gd:email');
//echo "<pre>"; print_r($result); die;
foreach ($result as $title) {
$emailsArr[] = (string) $title->attributes()->address;
}
}
}
}
Please help.
From previous experience (and this answer) I don't think cURL is enabled on App Engine as C extensions aren't supported.
You'll have to use URL Fetch instead e.g.
$data = ['data' => 'this', 'data2' => 'that'];
$data = http_build_query($data);
$context = [
'http' => [
'method' => 'GET',
'header' => "custom-header: custom-value\r\n" .
"custom-header-two: custom-value-2\r\n",
'content' => $data
]
];
$context = stream_context_create($context);
$result = file_get_contents('http://app.com/path?query=update', false, $context);
App engine supports cURL, but it seems to be buggy. I have the same problem with OAuth authentication via Google. The POST cURL call just returns FALSE without any error message. Here is the official bug report: https://code.google.com/p/googleappengine/issues/detail?id=11985
What you can do now, is to switch to url fetch functions. To make a POST request you can use following function:
protected function _call($url, array $params, $method = 'GET', array $headers = [])
{
$query = http_build_query($params);
$headers_str = '';
if ($headers) {
foreach ($headers as $name => $value) {
$headers_str .= $name . ': ' . $value . "\r\n";
}
}
$headers_str .= "Content-type: "."application/x-www-form-urlencoded"."\r\n";
$options =
array('http'=>
array(
'method' => $method,
'header' => $headers_str,
'content' => $query,
'ignore_errors' => true,
)
);
if ($method === 'POST') {
$options['http']['content'] = $query;
} else if ($query) {
$url .= '?' . $query;
}
$context = stream_context_create($options);
$response = file_get_contents($url, false, $context);
// check for zipped response and decode it
if (array_search('Content-Encoding: gzip', $http_response_header)) {
$response = gzinflate(substr($response, 10, -8));
}
return $response;
}
Or you can try to use this cURL wrapper library https://github.com/azayarni/purl, which was implemented before GAE provided cURL support. Hope it is helpful:)

How to split the oauth logic and create the Google Calendar service

I am using php client for Google Calendar API
https://github.com/google/google-api-php-client and CakePHP.
Basically, I just want to manage the events in the calendar.
And I could do it following the example here https://github.com/google/google-api-php-client/blob/master/examples/user-example.php. It worked fine (so, I have no problems with client id, client secret etc).
The only problem is that in the example it's all written in one file - the oauth logic and service specific logic (like retrieving events from calendar). So the redirect uri in google console points to the same file.
The pseudo-code for this is:
//here we create the client which is used for authentication
$client = new Google_Client();
//some of the oauth logic
$client->authenticate($_GET['code']);
//other oauth logic
$service = new Google_Service_Calendar($client);
$events = $service->events->list();
//...
So, as you see, to create a service we need a client (which contains the access token and all the authentication data needed for service).
I want to split it, so that I have the callback where I could retrieve the client and then use it for creating the service. I could have also specify that callback in google console as a redirect uri.
I have a feeling that there should be some standard way which unfortunately I am not aware of. I broke my head thinking about how to do this, so any help is appreciated.
Thanks.
UPDATE
As it often happens, right after posting a question here I managed to do something.
After we get an access token, we need to save it into DB.
Next time, when we want to do something with the api, we create the google client again and just set the access token with the value from the DB. So that we don't need to go through the oauth logic again.
Something like this:
$accessToken = $db->getOne('SELECT token FROM users WHERE id=:id');
$client = new Google_Client();
$client->setClientId($clientId);
$client->setClientSecret($clientSecret);
$client->setRedirectUri($redirectUri);
$client->setAccessType($accessType);
$client->setScopes($scope);
$client->setAccessToken(json_encode($accessToken));
Well, it looks obvious. But still I'd like to get an answer from experts to this question:
is recreating the google client object the right approach?
Thanks.
CakePHP 3.x in Google Calendar API
Follow this steps:
Create google calendar api
https://console.developers.google.com/flows/enableapi?apiid=calendar&pli=1
Composer to install:
"google/apiclient": "^2.0"
Required google calendar api integration
https://console.developers.google.com/flows/enableapi?apiid=calendar&pli=1
https://developers.google.com/google-apps/calendar/quickstart/php
Create project and create secret key and client id Project in set
name and redirect URL
NOTE:- redirect URL must be .com and .org
domain If you develop in local machine then create follow type of
virtual host example.com and example.org Virtual host create then
Follow this step:
Set configuration file in app_globle.php
'Google' => [
'ClientID' => '7441260037.apps.googleusercontent.com',
'ClientSecret' => 'kashdjahdkjshdkjhjAs',
'RedirectUrl' => 'http://' . env("HTTP_HOST") . '/oauth2calendars',
'ClientCredentials' => WWW_ROOT . 'files'. DS.'google.txt',
'Scopes' => implode(' ', [Google_Service_Calendar::CALENDAR, Google_Service_Drive::DRIVE, Google_Service_Drive::DRIVE_FILE, Google_Service_Drive::DRIVE_APPDATA, Google_Service_Drive::DRIVE_METADATA]),
]
Route
$routes->connect('/events/add', ['controller' => 'Events', 'action' => 'add', ['_name' => 'add-event']);
$routes->connect('/events/edit/:id', ['controller' => 'Events', 'action' => 'edit', ['id' => '\d+', 'pass' => ['id'], '_name' => 'edit-event']);
$routes->connect('/events/delete/:id', ['controller' => 'Events', 'action' => 'delete', ['id' => '\d+', 'pass' => ['id'], '_name' => 'delete-event']);
Controller
use Google_Client;
use Google_Service_Calendar;
use Google_Service_Calendar_Event;
use Google_Service_Drive;
use Google_Service_Drive_DriveFile;
Authorize the google Oauth thriugh
/**
* get Google calendar client
*/
private function getClient()
{
$client = new Google_Client();
$client->setAccessType("offline");
$client->setClientId(Configure::read('Google.ClientID'));
$client->setClientSecret(Configure::read('Google.ClientSecret'));
$client->setRedirectUri(Configure::read('Google.RedirectUrl'));
$client->setScopes(Configure::read('Google.Scopes'));
$credentialsPath = Configure::read('Google.Credentials');
if (file_exists($credentialsPath)) {
$accessToken = json_decode(file_get_contents($credentialsPath), true);
} else {
// Request authorization from the user.
$authUrl = $client->createAuthUrl();
return $this->redirect($authUrl);
}
$client->setAccessToken($accessToken);
// Refresh the token if it's expired.
if ($client->isAccessTokenExpired()) {
$client->fetchAccessTokenWithRefreshToken($client->getRefreshToken());
file_put_contents($credentialsPath, json_encode($client->getAccessToken()));
}
return $client;
}
/**
* Create Google Calendar event
*/
public function createCredentials()
{
$client = new Google_Client();
$client->setAccessType("offline");
$client->setClientId(Configure::read('Google.ClientID'));
$client->setClientSecret(Configure::read('Google.ClientSecret'));
$client->setRedirectUri(Configure::read('Google.RedirectUrl'));
$client->setScopes(Configure::read('Google.Scopes'));
if (isset($this->request->query['code'])) {
$client->authenticate($this->request->query['code']);
$token = json_encode($client->getAccessToken());
$credentialsPath =WWW_ROOT . 'files'. DS.'google.txt';
if (!file_exists(dirname($credentialsPath))) {
mkdir(dirname($credentialsPath), 0700, true);
}
$file = new File($credentialsPath, true);
$file->write($token);
$client->setAccessToken($token);
return $this->redirect(‘/add-event’);
}
}
Add event functionality
Public function add()
{
$client = $this->getClient();
if ($this->request->is('post')) {
$dateStart = new \DateTime($this->request->data['start_date_time'], new \DateTimeZone('Asia/Kolkata'));
$dateStart->setTimezone(new \DateTimeZone('UTC'));
$startDate = $dateStart->format('Y-m-d H:i:s');
$dateEnd = new \DateTime($this->request->data['end_date_time'], new \DateTimeZone('Asia/Kolkata'));
$dateEnd->setTimezone(new \DateTimeZone('UTC'));
$endDate = $dateEnd->format('Y-m-d H:i:s');
$guests = $this->request->data['guests'];
$eventGuest = [];
$service = new Google_Service_Calendar($client);
foreach ($guests as $key => $value) {
$eventGuest[$key]['email'] = $value;
}
$eventData = [
'summary' => $this->request->data['name'],
'location' => $this->request->data['location'],
'description' => $this->request->data['description'],
'start' => [
'dateTime' => date("c", strtotime($startDate)),
],
'end' => [
'dateTime' => date("c", strtotime($endDate)),
],
'attendees' => $eventGuest,
'reminders' => [
'useDefault' => true,
],
'visibility' => 'private',
'privateCopy' => true,
];
$event = new Google_Service_Calendar_Event($eventData);
$sendNotifications = ['sendNotifications' => true];
$calendarId = 'primary';
$eventDataResponse = $service->events->insert($calendarId, $event, $sendNotifications);
}
}

Testing laravel controllers with JSON request body

I am trying to write a phpunit test for a Laravel controller which expects post requests with a body in JSON format.
A simplified version of the controller:
class Account_Controller extends Base_Controller
{
public $restful = true;
public function post_login()
{
$credentials = Input::json();
return json_encode(array(
'email' => $credentials->email,
'session' => 'random_session_key'
));
}
}
Currently I have a test method which is correctly sending the data as urlencoded form data, but I cannot work out how to send the data as JSON.
My test method (I used the github gist here when writing the test)
class AccountControllerTest extends PHPUnit_Framework_TestCase {
public function testLogin()
{
$post_data = array(
'email' => 'user#example.com',
'password' => 'example_password'
);
Request::foundation()->server->set('REQUEST_METHOD', 'POST');
Request::foundation()->request->add($post_data);
$response = Controller::call('account#login', $post_data);
//check the $response
}
}
I am using angularjs on the frontend and by default, requests sent to the server are in JSON format. I would prefer not to change this to send a urlencoded form.
Does anyone know how I could write a test method which provides the controller with a JSON encoded body?
In Laravel 5, the call() method has changed:
$this->call(
'PUT',
$url,
[],
[],
[],
['CONTENT_TYPE' => 'application/json'],
json_encode($data_array)
);
I think that Symphony's request() method is being called:
http://symfony.com/doc/current/book/testing.html
This is how I go about doing this in Laravel4
// Now Up-vote something with id 53
$this->client->request('POST', '/api/1.0/something/53/rating', array('rating' => 1) );
// I hope we always get a 200 OK
$this->assertTrue($this->client->getResponse()->isOk());
// Get the response and decode it
$jsonResponse = $this->client->getResponse()->getContent();
$responseData = json_decode($jsonResponse);
$responseData will be a PHP object equal to the json response and will allow you to then test the response :)
Here's what worked for me.
$postData = array('foo' => 'bar');
$postRequest = $this->action('POST', 'MyController#myaction', array(), array(), array(), array(), json_encode($postData));
$this->assertTrue($this->client->getResponse()->isOk());
That seventh argument to $this->action is content. See docs at http://laravel.com/api/source-class-Illuminate.Foundation.Testing.TestCase.html#_action
There is a lot easier way of doing this. You can simply set Input::$json property to the object you want to send as post parameter. See Sample code below
$data = array(
'name' => 'sample name',
'email' => 'abc#yahoo.com',
);
Input::$json = (object)$data;
Request::setMethod('POST');
$response = Controller::call('client#create');
$this->assertNotNull($response);
$this->assertEquals(200, $response->status());
I hope this helps you with your test cases
Update : The original article is available here http://forums.laravel.io/viewtopic.php?id=2521
A simple solution would be to use CURL - which will then also allow you to capture the 'response' from the server.
class AccountControllerTest extends PHPUnit_Framework_TestCase
{
public function testLogin()
{
$url = "account/login";
$post_data = array(
'email' => 'user#example.com',
'password' => 'example_password'
);
$content = json_encode($post_data);
$curl = curl_init($url);
curl_setopt($curl, CURLOPT_HEADER, false);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_HTTPHEADER, array("Content-type: application/json"));
curl_setopt($curl, CURLOPT_POST, true);
curl_setopt($curl, CURLOPT_POSTFIELDS, $content);
$json_response = curl_exec($curl);
$status = curl_getinfo($curl, CURLINFO_HTTP_CODE);
curl_close($curl);
$response = json_decode($json_response, true);
// Do some $this->Assert() stuff here on the $status
}
}
CURL will actually simulate the raw HTTP post with JSON - so you know you are truly testing your functionality;
As of Laravel 5.1 there is a much easier way to test JSON controllers via PHPunit. Simply pass an array with the data and it'll get encoded automatically.
public function testBasicExample()
{
$this->post('/user', ['name' => 'Sally'])
->seeJson([
'created' => true,
]);
}
From the docs: http://laravel.com/docs/5.1/testing#testing-json-apis
Since at least Laravel 5.2 there is a json() method in Illuminate\Foundation\Testing\Concerns\MakesHttpRequests therefore you can do the following:
$data = [
"name" => "Foobar"
];
$response = $this->json('POST', '/endpoint', $data);
Also since Laravel 5.3 there are also convenient methods like putJson(), postJson(), etc. Therefore it can be even shortened further to:
$data = [
"name" => "Foobar"
];
$response = $this->postJson('/endpooint', $data);
And then you can do $response->assertJson(...) like:
$response->assertJson(fn (AssertableJson $json) => $json->hasAll(['id', 'name']));

Cakephp 2.0 SMTP settings on Email not working

I am using SMTP to send email in my CAKEPHP Project.
My email config as follows
class EmailConfig {
public $Smtp = array(
'transport' => 'Smtp',
'from' => array('contact#mydomainname.com' => 'domainname.com'),
'host' => 'myhostingserver',
'port' => 2525,
'timeout' => 60,
'username' => 'username#mydomainname.com',
'password' => 'secret',
'client' => null,
'log' => false
);
and my Mail Functionality code as follows
$email = new CakeEmail('Smtp');
$result = $email->template('welcome_mail','default')
->emailFormat('html')
->to($to_email)
->from('contact#mydomainname.com')
->subject('Welcome to my domain name')
->viewVars($contents);
if($email ->send('Smtp'))
{
echo ('success');
}
While i am sending mail its throwing following error SMTP timeout. My SMTP Server details are correct its working fine in an existing server. I don't know where I am wrong
Check the encryption type (if applicable), e.g. ssl or tls
Your host URL should look something like this in such case
'host' => 'ssl://myhostingserver'
or
'host' => 'tls://myhostingserver'
If your SMTP server has SSL,you have to enable php_openssl in php.ini to use this service.
You can use this code to test
if(!in_array('openssl',get_loaded_extensions())){
die('you have to enable php_openssl in php.ini to use this service');
}
beside what here already was sugested here that the module must be loaded. i found that some servers have some ports blocked. i used this script to test some servers:
<?php
if(!in_array('openssl',get_loaded_extensions())){
die('you have to enable php_openssl in php.ini to use this service');
} else {
echo "php_openssl in php.ini is enabled <br />";
}
// fill out here the smpt server that you want to use
$host = 'ssl://smtp.gmail.com';
// add here the port that you use for for the smpt server
$ports = array(80, 465);
foreach ($ports as $port)
{
$connection = #fsockopen($host, $port);
if (is_resource($connection))
{
echo $host . ':' . $port . ' ' . '(' . getservbyport($port, 'tcp') . ') is open.<br />' . "\n";
fclose($connection);
} else {
echo $host . ':' . $port . ' is not responding.<br />' . "\n";
}
}
?>

Resources