Showing posts with label PHP. Show all posts
Showing posts with label PHP. Show all posts

Friday, March 19, 2021

How to solve proxy_fcgi:error AH01071: Got error 'Unable to open primary script

 Hello,

Recently I got stuck with strange bug on centOS server. After I updated document root for my primary domain which has Laravel App installed. 

When we try to access app through domain, we got following error. 

No input file specified.

I initially thought it's the permission issue on .htaccess issue. Tried changing permissions and adding some rewrite rules but it didn't work. When I checked apache error logs. I got following error. 

proxy_fcgi:error AH01071: Got error 'Unable to open primary script

I had no idea how to solve this error. So tried few things like

  • Restart apache
  • Restart php-fpm
  • Restart VPS
  • Removed and added account few times.
  • Disabling php-fpm
But nothing worked. I spent almost entire night in solving this issue but no luck. But finally I was able to solve the issue by following steps. It was actually the issue with php fpm, as it was not able to find out root folder for the domain. So here is what you have to do. 

First go to userdata directory 

/var/cpanel/userdata/<USERNAME>

Here you will find one file. 

yourdomain.com.php-fpm.yaml

Open this file with nano or vim editor and add following line at the end of it. 

php_admin_value_doc_root: { name: 'php_admin_value[doc_root]', value: /home/<USERNAME>/public_html/<DOCUMENT_ROOT> }

Save the file and then execute following commands one by one.

/scripts/php_fpm_config --rebuild 

/scripts/restartsrv_apache_php_fpm 

/scripts/restartsrv_httpd

This will rebuild php fpm config and restart php fpm service for apache. Now in the same folder open 

YOURDOMAIN.com 

YOURDOMAIN.com_SSL

Change document root here as well and run following commands.

/scripts/rebuildhttpdconf 

/scripts/restartsrv_httpd

This will rebuild apache config file and restart apache. 

This is it and now if you visit your domain, you will not have the issue of file missing. 

Hope this saves your time

Saturday, September 5, 2020

Create Secure Web Socket (WSS) with Ratchet PHP

Hello,

Recently I was working on PHP project where we I was create secure web socket which is accessible with wss:// protocol. For this I struggled for couple of hours so here in blog I am going to explain how to do that so it can save your time. 

Earlier version was not supporting WSS but later it introduced React socket server which allows SSL connection. So here are steps you need to follow. 

First add all the required classed in your php file.


use Ratchet\Server\IoServer;

use Ratchet\Http\HttpServer;

use Ratchet\WebSocket\WsServer;

use MyApp\Socket;


In above example Socket is my class file which has all listeners. After this add auto load file.

require dirname( __FILE__ ) . '/vendor/autoload.php';

Next we will create our socket app. 

$app = new \Ratchet\Http\HttpServer(
    new \Ratchet\WebSocket\WsServer(
        new \MyApp\Socket()
    )
);

Now next step is to create React Secure server.

$loop = \React\EventLoop\Factory::create();
$webSock = new \React\Socket\Server('0.0.0.0:8080', $loop);

We are using 0.0.0.0  so this socket can be connected from anywhere. 

Now lets create secure server by adding path to certificate and key

$webSock = new \React\Socket\SecureServer($webSock, $loop, [
    'local_cert' => 'CRT_PATH', 
    'local_pk'=> 'KEY_PATH', 
    'allow_self_signed' => true, 
    'verify_peer' => false
]);

Now finally we will run our server.

$webSock = new \Ratchet\Server\IoServer($app, $webSock, $loop);
$webSock->run();

That's it. It will start your server to which you can connect with WSS protocol. To test you can use WebSocket ECHO test.


Hope this helps you.

Thursday, August 20, 2020

AWS PHP SDK - Create an Entry in Route53 - Laravel

 Hello,

In this blog I will explain you how to you can create an entry in Route53 hosted zone using AWS PHP SDK. Solution I mentioned here is particularly for Laravel app, but you can still use it in any of the PHP project. 

This solution is pretty much useful when you want to make a dynamic entry in your hosted. For example a dynamic sub domain creation. 

First of all your need install couple of packages using composer. Following are the packages. 

"aws/aws-sdk-php": "^3.148",

"aws/aws-sdk-php-laravel": "~3.0",

You can either install it by adding it in composer.json file or you can install it using composer require. 

Once the installation is done, follow the steps mentioned in below URL. 

https://github.com/aws/aws-sdk-php-laravel

Once installation is done. You need to add following keys in your env file.

AWS_ACCESS_KEY_ID

AWS_SECRET_ACCESS_KEY

AWS_REGION (default = us-east-1)

Set the values in above keys from your AWS account. That's it your AWS SDK is ready. Now add following line your controller where you want to have logic for adding value in Route53

use Aws\Route53\Route53Client;

use Aws\Common\Credentials\Credentials;

Now next step is to create a client

$client = Route53Client::factory(array(

            'credentials' => config('aws.credentials'),

            'region' => config('aws.region'),

            'version' => config('aws.version'),

)); 

After client is created we will use changeResourceRecordSets to create an entry.

$result = $client->changeResourceRecordSets(array(

            // HostedZoneId is required

            'HostedZoneId' => 'YOUR_HOSTED_ZONE_ID',

            // ChangeBatch is required

            'ChangeBatch' => array(

                'Comment' => 'string',

                // Changes is required

                'Changes' => array(

                    array(

                        // Action is required

                        'Action' => 'CREATE',

                        // ResourceRecordSet is required

                        'ResourceRecordSet' => array(

                            // Name is required

                            'Name' => 'YOUR_VALUE',

                            // Type is required

                            'Type' => 'CNAME', //A, CANME

                            'TTL' => 600,

                            'ResourceRecords' => array(

                                array(

                                    // Value is required

                                    'Value' => 'YOUR_VALUE', //IP address or load balancer.

                                ),

                            ),

                        ),

                    ),

                ),

            ),

        ));

That's it and it will create an entry in Route53 hosted zone. 

Sunday, March 22, 2020

Laravel App Connect and Emit to Socket.io

Hello,

Recently in one of the project I was working on we have socket.io server created using NodeJS and there were couple of Angular applications and android applications connects with it. However there was a requirement to connect with socket from Laravel app and emit the event.

Actually there was a form in Laravel app on submit of Form we have to notify the socket and socket further notify all the clients connected to it. In this blog I am going to mention how we solved this.

We all know Laravel by default comes with integration of Pusher we could have used it. But since Socket.io is free so we consider to use Socket.io.

Let's go step by step and understand how to connect with Socket.io

Step 1

Create new folder socket in your app directory of Laravel app.

Step 2

Copy following class in to app/Socket folder and rename it to SocketIO.php

https://github.com/psinetron/PHP_SocketIO_Client

There are many PHP socket IO client is available but we used above one. You can choose either one of your choice.

Step 3

Connect and emit to socket. In your controller file where you want to emit the event. Add following code.

$socketIO = new SocketIO();
$returnValue = $socketIO->send('YOUR_URL', YOUR_PORT, 'YOUR_EVENT',json_encode(YOUR_PHP_ARRAY))

For this add following line to top of your controller.

use App\socket\SocketIO;

That's it and now you can connect with socket and emit event to it.

Sunday, May 5, 2019

Laravel Mail Queue Get Receiver User

Hello,

Recently in one my Laravel project faced an issue where in Mail we have to change content dynamically based on receiver. As we know that when we use Mailable class and mail queue, mail will not sent immediately but it will be processed with Mail Queue. Here we don't have Auth Session or any other information to get receiver user.

To solve this I used following trick.

In mailable class if you check $this variable it will give all such information like this.

from-> => "norply@xyz.com"
address-> : Array[
    0 => Array[
          "address" => "hdave10@gmail.com"
    ]
]

From here you can access email address like this

$emailOfReceiver = $this->to[0]["address"];

And using this you can find user object from Auth\User model or your own model which you used for user information in your laravel project. For my case I was using EmployeeMaster model to get additional information.

Following line I have used in one my Mailable class.

$employee = EmployeeMaster::where("emp_email",$this->to[0]["address"])->first();

Now with this I can write my logic to dynamically change the content of mail.

Hope this helps you.

Wednesday, February 13, 2019

Laravel - Connect With Multiple Database

Hello,

In this blog post I am going to mention how we can connect multiple databases with Laravel applications. First add multiple connections in config/database.php For this copy paste mysql connection and change configurations as following.

'mysql1' => [
            'driver' => 'mysql',
            'host' => env('DB_HOST', '127.0.0.1'),
            'port' => env('DB_PORT', '3306'),
            'database' => env('DB_DATABASE_1',''),
            'username' => env('DB_DATABASE_1_USERNAME',''),
            'password' => env('DB_DATABASE_1_PASSWORD',''),
            'unix_socket' => env('DB_SOCKET', ''),
            'charset' => 'utf8mb4',
            'collation' => 'utf8mb4_unicode_ci',
            'prefix' => '',
            'strict' => false,
            'engine' => null,
        ],

Now add these values in .env file

DB_DATABASE_1=YOUR_DB_NAME
DB_DATABASE_1_USERNAME =YOUR_USER_NAME
DB_DATABASE_1_PASSWORD = YOUR_PASSWORD

Now laravel give you two ways to switch database connection.

1) Set connection property in Eloquent Model

protected $connection = 'mysql1';

So here when you use this model to get data it will use the connection specified in the mysql1. You don't need to manually change it. 

2) use DB:connection 

If you are using raw queries and using DB facade so to get query the data. You have to use following logic.

DB::connection('mysql1')->table(env('DB_DATABASE_1','')).'.TABLE_NAME')


So here first you have specified connection and then used table by appending db name in front of it. 

So this is how you can manage multiple databases.


Tuesday, December 11, 2018

Laravel Check if SMTP Connection is valid

Hello,

While working with Laravel we often add SMTP credentials to send mail. It's important to check SMTP connection before sending mail or else it may give you error and throw run time exception. Here in this blog I am going to explain how to check SMTP connection before sending mail.

Below is the code you can use to check.

try {
$security = ($request->get('mail_encryption') != 'None') ? request()->get('mail_encryption') : null;
$transport = new \Swift_SmtpTransport($request->get('mail_host'), $request->get('mail_port'), $security);
$transport->setUsername($request->get('mail_username'));
$transport->setPassword($request->get('mail_password'));
$mailer = new \Swift_Mailer($transport);
$mailer->getTransport()->start();
}
catch (\Swift_TransportException $e) {
return redirect('mailSettings')->withInput()->with(array('message'=>'Can not connect to SMTP with given credentials.'));
}

As you can see in above code, first we are setting security config and create Swift_SmtpTransport class. After this we add add username and password. After that we create Swift_Mailer class and check it, if it throws an exception that means credentials are wrong or else credentials are correct.

Laravel Create Custom Validator

As we all know that Laravel comes with in built set of custom validators like required, unique etc using which we can do form or request validations on server side. In this blog I am going to explain how to create custom validator.

Custom validator is required when you have some special logic validations. For example a field should be minimum of 12 characters, it should start with special prefix etc.

To do this Laravel provides way to create custom field validator. You have to extend Validator in boot method of AppServiceProvider. Here is the complete code.

use Validator;

public function boot()
{
        Validator::extend('VALIDATOR_NAME', function($attribute, $value, $parameters, $validator) {
               //validation logic
               //should return true or false
        });

       Validator::replacer('greater_than_field', function($message, $attribute, $rule, $parameters) {
  return $attribute."MESSAGE".$parameters[0];
});
}

As you can see in above code, first we define validator with Validator::extend and then using Validator::replacer we can define the message to be displayed.

This way you can create your own validators and then use it with Validator class.

$this->validate($request, [
          'field'=>'VALIDATOR_NAME'
]);

Thursday, November 1, 2018

Laravel : Better Way To Deal with Trying to Get Property Of Non Object

Hello Everyone,

After a gap of almost 3 months I am again writing a blog. In laravel project we sometimes face issues like we try to access model but it's not available due to various reason like
  • id we passed is wrong
  • we manually deleted records from database
  • wrong value saved in database.
  • wrong model you are trying to access with wrong value.
When we get this error, Laravel throws an ErrorException with message "Trying to get property of non object."

However, end user does not understand this error so we have to show them proper message on what's missing. We can not display generic error page and for each line of code we can not put the check so better to check it at single place. Laravel gives this functionality in Exception Handler. Here the trick is to get model which throws this error and get name of Model and display proper message. 

Laravel has class ModelNotFoundException which is thrown when you use findOrFail function. However we developers sometime do not use this function and use find function. 

When find function is used, it throws ErrorException which does not contain Model information. However we can modify Laravel source code for this. 

Open following file 

vendor/laravel/framework/src/Illuminate/Database/Eloquent/Builder.php

Here find public function find($id, $columns = ['*'])

and modify it as following.

        if (is_array($id) || $id instanceof Arrayable) {
            return $this->findMany($id, $columns);
        }
        $object = $this->whereKey($id)->first($columns);
        if($object == null){
            throw (new ModelNotFoundException)->setModel(
                get_class($this->model), $id
            );
        }else{
            return $this->whereKey($id)->first($columns);
        }

PLEASE NOTE : I DO NOT RECOMMEND TO MODIFY SOURCE FILE SO BETTER WAY IS TO USE FINDORFAIL FUNCTION.

Now if you use find or findOrFail function it will throw ModelNotFoundException. Now open app/Exception/Handler.php file and find out function public function render($request, Exception $exception)

Add following code at start of the function.

       if(get_class($exception) == 'Illuminate\Database\Eloquent\ModelNotFoundException'){
            $modelName = explode("\\",$exception->getModel());
            $modelName = $modelName[count($modelName)-1];
            $message = "You are trying to access ".$modelName." which does not exist.";
                return Response::make(view('Frontend.error')->with(array(
                    "message"=>$message
            )));
        }

That's it and now it will display proper message like

You are trying to access User which does not exist.
You are trying to access Post which does not exist.

Hope this helps you.

Wednesday, August 1, 2018

Laravel Allow Single Login Only

Hello,

Recently in one of my project we need functionality to allow only single session for user. So if I am logged in with one user account then I can not use it on other device. If they try to do so, it will log you out from first last session and will continue with current session.

So here is the trick I have used is to store active session id to users table and then check it with new session id on login. If both are not same then destroy the old session.

So first of all create migration and add session id column in users table.

Schema::table('users', function($table)
        {       
            $table->string('session_id')->nullable();
        });

Now in your AuthController or LoginController add following function after user is authenticated.

$user = \Auth::user();
$currentSessionId = $request->session()->getId();
if($lastSessionId != null){
if($currentSessionId != $lastSessionId){
//destroy last session
\Session::getHandler()->destroy($lastSessionId);
}
}
$user->session_id = $currentSessionId;
$user->save();

So here it will destroy old session and create new one. Please note this is one way to achieve single login. There could be better trick, in that case please share here.lara

Saturday, July 21, 2018

Step By Step : Laravel - Publish Post on Facebook Page with Graph API

Hello,

In this quick blog we will quickly go through how to publish a post on Facebook Page with graph API from your Laravel Application.

Step 1 : Create Facebook App

Login to https://developers.facebook.com/ with your Facebook account and create an app.

Now go to Settings -> Basic of your Facebook app and copy app id and app secret.


Step 2 : Install Facebook PHP SDK

Run following command to install PHP SDK in your laravel application.

composer require facebook/graph-sdk

Step 3: Get Exchange Token from Facebook App

Go to Facebook Graph API Explorer. Here is the link  https://developers.facebook.com/tools/explorer/

From here first select your application and then select the page for Page Access Token


When you are generating this token please select graph API version 2.2 and select the following permissions.

publish_actions, 
manage_pages, 
pages_show_list, 
publish_pages, 
public_profile

Step 4 : Generate Access Token 

From the exchange token generated in Step 3, Get the access token.

$url = 'https://graph.facebook.com/oauth/access_token?grant_type=fb_exchange_token&client_id= YOUR_APP_ID&client_secret= YOUR_APP_SECRET&fb_exchange_token=YOUR_TOKEN';

$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, $url);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
$result = curl_exec($curl);
$output = json_decode($result);
$access_token = $output->access_token;

Step 5 : Call Facebook Graph API to Send Post to Page

Create SDK object

$fb = new \Facebook\Facebook([
'app_id' => 'YOUR_APP_ID',
'app_secret' => 'YOUR_APP_SECRET',
'default_graph_version' => 'v2.2',
]);

Generate Payload

$linkData = [
 'link' => YOUR_LINK,
 'message' => YOUR_TITLE
];

Call Graph API.

$pageAccessToken =$access_token;

try {
 $response = $fb->post('/me/feed', $linkData, $pageAccessToken);
} catch(Facebook\Exceptions\FacebookResponseException $e) {
 echo 'Graph returned an error: '.$e->getMessage();
} catch(Facebook\Exceptions\FacebookSDKException $e) {
 echo 'Facebook SDK returned an error: '.$e->getMessage();
}
$graphNode = $response->getGraphNode();

Now check your Facebook page there will be post on your Facebook page. Hope this helps you.

Friday, April 20, 2018

Laravel ValidationException Handling

This is the creepiest thing I have ever fixed in Laravel. I can't even imagine that in Laravel we can have such creepy problem. But anyways other than this I really like Laravel framework.

First let me explain the problem. In our Laravel 5.5 application we have added exception handling in app/Exceptions/Handler.php file

public function render($request, Exception $exception)
{
    Redirect::to('admin/errorPage')->send();
}

Now the problem was in case of form validations it was throwing ValidationException so in case of returning back to form it always took me to the error page and I am not able to see what are the validation issues. Now that was really strange. So there were two options . First, I have to remove server side validations so it does not throw ValidationException and we shall do all client side validations. Or find out some other way to handle this.

So after 3 to 4 hours of struggle of going though framework code and documentation and online help I finally figure out the solution. Here are steps to add it.

1) Step 1 : Add  ValidationException in dontReport field in app/Exceptions/Handler.php

protected $dontReport = [
   //
   \Illuminate\Validation\ValidationException::class
];

2) Step 2 : Update the render method declaration

public function render($request, Exception $exception)
{
    if($this->shouldReport($exception)){
       Redirect::to('admin/errorPage')->send();
    }else{
       return $this->convertValidationExceptionToResponse($exception, $request);
    }
}

So here first we are checking if the current exception to be reported or not by checking shouldReport function

If not to be reported then we are using convertValidationExceptionToResponse method of super class to generate the response and send it back.

Please note that this solution will only work

Sunday, February 11, 2018

OSX MAMP, Update PHP Version

Hello,

So recently I was working on Laravel Lumen framework where we need PHP 7.1.3 version. In my OSX XAMPP was using php version 7.1.1

So here in this blog I am going to explain step by step procedure.

Step 1: Go to MAMP website and download the new version of PHP. Go to following link

MAMP Downloads

On left side you will see column with title "Additional PHP versions"

There you will find list of PHP versions for OSX, download the one which you want and extract it. Copy it to

MAMP\bin\php folder.

For example if you download php version 7.1.3 then you will get folder with name

php7.1.3

Now you have to make two changes.

First edit path in your bash profile and update the existing path of PHP to newer version.


export PATH=/Applications/MAMP/bin/php/php7.1.3/bin:$PATH

After this quit the MAMP and restart it. It should work. No wait still it may not work for you.  As you go to MAMP preference screen, you will see that still it's using old version and new version is not displayed there.


That's because, by default free version of MAMP displays only last two folder here. So trick is to delete old folder or rename it and now your version of PHP will be displayed. Select it click on OK, restart MAMP and that's it now you get newer version of PHP. 

Hope this helps you.



Sunday, February 4, 2018

Some Tips and Tricks of Working With Bootstrap Select2 Control

Hello,

Since I am a web developer, I used to work  a lot with Bootstrap Select 2 Control. Here I am going to share some quick tips and tricks of working with Select 2 controls.

1) Dynamically create Select2 control with JavaScript

When we are working on dynamic websites, sometimes we also have to create select2 controls dynamically. Most of the developers faces issues here. Because select2 control is created by JavaScript on document ready. So if you want create it dynamically, first append basic html of control inside and the by using JavaScript init it.

Something like this.

$('.select2').select2();

Sometimes it takes time to get reflect in DOM so in this case you may have to give some timeout.

setTimeout(function(){
      $('.select2').select2();
},500);

2) Open Select2 dropdown on focus.

This is one more UX experience. Most of the web users are used to work with TAB. So in your form if you have select2 control and you come on it via tab. It should open dropdown.

Here is how we can do it.

$(document).on('focus', '.select2', function() {
if($(this).prev().val() == ''){
  $(this).siblings('select').select2('open');
}
});

3) Open Select2 dropdown with down arrow key

This is one more UX experience. Most of the web users are used to work with up and down arrow while working with dropdown. So in case of select2 they are expecting the same result.

$(document).on('keydown', '.select2', function(event) {
    if(event.keyCode == 40){
    $(this).siblings('select').select2('open');
    }
});

4) Keep focus on Select2 after selecting item and dropdown is closed.

In new version of Select2 there is a bug that after you select an item and dropdown is closed. It will lost focus. So to keep focus on the control, use following code.

$('select').on(
  'select2:close',
  function () {
  $(this).focus();
  }
  );
},1000);

Hope this tips helps you in your development with Select2.

Friday, February 2, 2018

Amazon EC2 Laravel Not Live After " php artisan up " Command

Hello,

This blog post is about quick tip for the users who have deployed Laravel application on Amazon EC2 instance.

Recently we had Laravel application deployed on Amazon EC2 instance where we put site on maintenance mode with command

php artisan down

Worked properly, site was in maintenance mode and displayed

Be Right Back screen.

After sometime we tried to make site up and running by

php artisan up

Didn't work as site was still displaying

Be Right Back screen

Tried to clear the cache and config with

php artisan cache:clear
php artisan config:clear

But still it didn't worked. After 5 to 10 mins to struggle, found out an issue. It was because of file permission issue.  When you put site to maintenance mode, it creates

storage/framework/down folder

When you run

php artisan up

This folder should be removed. However in my case I was not using root user hence this file was not deleted.

So solution is

go to storage/framework folder and run command

rm -rf down

and that's it, your site is up and live.

Hope this helps you. 

Wednesday, November 8, 2017

Laravel Query Builder GroupBy Syntax error or access violation

Hello,

Recently I forked a Github project and was updating it. I faced strange issue in using GroupBy in query builder. I was trying to query model as follow.

$projects = ProjectReviews::groupBy('project_id')->orderBy('created_at','DESC')->get();

Basically I wanted to get recently reviewed projects and show dates. But in above query I was getting error Syntax error or access violation project_reviews.id isn't in group by.

That was really strange issue as that's the primary key of table and it should not be part of group by. If you run that query directly in PHP MyAdmin it was working fine. So I was not sure about this. Finally after spending couple of hours I was able to find out the problem.

It's because of strict config settings of database. If you look into config/database.php file there is strict config there.

        'mysql' => [
            'driver' => 'mysql',
            'host' => env('DB_HOST', '127.0.0.1'),
            'port' => env('DB_PORT', '3306'),
            'database' => env('DB_DATABASE', 'forge'),
            'username' => env('DB_USERNAME', 'forge'),
            'password' => env('DB_PASSWORD', ''),
            'unix_socket' => env('DB_SOCKET', ''),
            'charset' => 'utf8mb4',
            'collation' => 'utf8mb4_unicode_ci',
            'prefix' => '',
            'strict' => true,
            'engine' => null,
        ],

You have to set to false to make GroupBy working.

Following is mentioned in MySql Documentation for this config.

Strict mode controls how MySQL handles invalid or missing values in data-change statements such as INSERT or UPDATE. A value can be invalid for several reasons. For example, it might have the wrong data type for the column, or it might be out of range. A value is missing when a new row to be inserted does not contain a value for a non-NULL column that has no explicit DEFAULT clause in its definition. (For a NULL column, NULL is inserted if the value is missing.) Strict mode also affects DDL statements such as CREATE TABLE.
So basically it secures your database operations. However in Laravel it's not working properly. So I was not sure if it's laravel bug. But I had to disable it make this query working.

Disabling it wouldn't make your web app unsecured if you handle all validations in your controllers and follow best practices like Laravel already does.

However I still recommend to be careful, while using this.

Monday, August 28, 2017

Using Google Translation API For Indian Language with PHP

Google translation API works good for Indian languages, if we type in proper language. For example, if you pass following in API. 

कैसे हो

Then it will translate properly to 

how are you

But if you pass it in english, like this.

"KAISE HO"

Then it will send the same text back but it only detects language. So it does not work properly. So what shall the possible solution for it. 

Here is how I worked out in one of my old project.

First I used Google input tools API to convert the input to regional language. 

So steps if First

KAISE HO is converted to

कैसे हो

and then pass it in translation API to convert it to English. Here is the code for the same.

$translatedText = "KAISE HO";
$detectedSourceLanguage = "hi";

$url ='https://www.google.com/inputtools/request?text='.urlencode($translatedText).'&ime=transliteration_en_'.urlencode($detectedSourceLanguage);

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER,1);
curl_setopt($ch, CURLOPT_PROXYPORT,3128);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST,0);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER,0);
$response = curl_exec($ch);
$output = json_decode($response);
$resultText = '';

if($output[0] == 'SUCCESS'){
if(isset($output[1])){
if(isset($output[1][0])){
if(isset($output[1][0][1])){
$resultText = $output[1][0][1][0];
}
}
}
}

if($resultText != ''){
$url ='https://translation.googleapis.com/language/translate/v2';
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS,
"q=".urlencode($resultText)."&target=en&key=YOUR_API");

curl_setopt($ch, CURLOPT_RETURNTRANSFER,1);
curl_setopt($ch, CURLOPT_PROXYPORT,3128);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST,0);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER,0);
$response = curl_exec($ch);
$output = json_decode($response);
$resultText = $output->data->translations[0]->translatedText;
}

Hope this helps you in proper translation.

Friday, August 25, 2017

Laravel Dynamic Mail Configuration With Values From Database

In Laravel we have config folder, where we have different files like app.php and mail.php etc where we can configure settings. For example for sending mail from Laravel application, we have to configure mail.php file with configs like mail driver, mail user name etc. This will work good for static information. But what if you want to override and use your own settings from database at run time.

For example you have different mail configurations for each users and you want to set it when user is logged in. I this blog I am going to show you how you can do this in Laravel 5.x

For example you have mail_settings table where you are saving mails settings for each user. Now when user is logged in we have to get settings of logged in user and set it in config. This is how you can do that.

We know that all laravel controller extends the Controller. So what you can do is in constructor of Controller.php file, you can set the mail settings.

Here is how you can do this.
public function __construct()
{
$this->middleware(function ($request, $next) {
if(Auth::user()){
//So user is logged in.
if(Auth::user()->parent_id != null){
//Get the mail settings.
$settings = MailSettings::where('user_id',Auth::user()->parent_id)->first();

if(isset($settings)){
//settting up mail config for the logged in user.
config( ['mail' => ['from' => ['address' => $settings->from_email, 'name' => $settings->from_name], 'host'=>$settings->mail_host, 'port'=>$settings->mail_port, 'username'=>$settings->mail_username,  'password'=>$settings->mail_password, 'encryption'=>$settings->mail_encryption, 'driver'=>$settings->mail_driver]]);
}
}
}
return $next($request);
});

}

So as you can see we are getting mail settings from table for logged in user and setting up it in config. This way you can override anything in the default config and set it run time.

Monday, August 7, 2017

Integrating GetStream with Laravel using stream-laravel for Real Time Notifications

Hello,

After a long time I am publishing a blog post. I am sorry to all my readers for not publishing blog for longer time. In this blog I am going to explain how you can have real time notifications in your laravel application using GetStream.io.

I will not go in installation details as it's very well documented on their Github page. You can refer it here.

GetStream/steam-laravel

After you have installed it and configured service provider. First thing you have to do is create table for notifications. For that create migration add following code to it.

Schema::create('notifications', function (Blueprint $table) {
$table->increments('id');
$table->integer('user_id')->index();
$table->string('name');
$table->string('message');
$table->string('link');
$table->timestamps();
});

Now create a model with name Notifications and add following code to it.


namespace App\Http\Models;

use App\User;
use Illuminate\Database\Eloquent\Model;

class Notifications extends Model
{
    //
    use \GetStream\StreamLaravel\Eloquent\ActivityTrait;
    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $table = 'notifications';

    protected $fillable = ['name', 'message','link'];
   
    /**
     * The attributes that should be cast to native types.
     *
     * @var array
     */
    protected $casts = [
        'user_id' => 'int',
    ];
    /**
     * Get the user that owns the task.
     */
    public function user()
    {
        return $this->belongsTo(User::class);
    }
    /**
     * Stream: Add extra activity data - task name, and user's display name:
     */
    public function activityExtraData()
    {
        return array('name'=>$this->name, 'message' => $this->message, 'link'=> $this->link);
    }
   /**
    * Stream: Change activity verb to 'created':
    */
    public function activityVerb()
    {
        return 'created';
    }

}


Now open your user model and add following code to it.

public function notifications()
    {
        return $this->hasMany(Notifications::class);
    }

So now we have notifications table setup and it's linked to user with hasMany relationship. Now next we will show how you can create notification.

$userObject->notifications()->create([
'name' => "NOTIFICATION_NAME",
'message' => 'NOTIFICATION_MESSAGE',
'link' => 'NOTIFICATION_LINK'           
]);

Here userObject is the object of user for whom you want to create notification. Now next we will show how to get all the notifications and show it user. For this we are going to use AngularJs. 

We are using client side library of GetStream.io you can download it from following link.


For this first of all we have to get token and that can be generated only from server side code. So create an API and call it from AngularJs controller. Here is the API code.

public function getStreamToken(){
$feed = \FeedManager::getUserFeed(Auth::user()->id);
$token = $feed->getToken();

return Response::json(array("success"=>true,"token"=>$token,"user_id"=>Auth::user()->id));
}

Now as soon as we get token, next you have to connect to client and get user feeds and register for push notifications. Here is the code for the same.

var client = stream.connect('YOUR_API_KEY', null, 'YOUR_APP_ID');
$scope.user = client.feed('user', $scope.user_id, $scope.token);

function successCallback() {
console.log('now listening to changes in realtime');
}

function failCallback(data) {
console.log(data);
}

$scope.user.subscribe($scope.gotNotification).then(successCallback, failCallback);    

$scope.user.get({limit:10, offset:$scope.offset}, $scope.gotUserActivities);

So above code will register you for the push notification and will get all your notifications. Now you have to display it using HTML and CSS as per your wish. 

For showing new notification, you can use below code in gotNotification function.

$.bootstrapGrowl(data.new[0].name + ' ' + data.new[0].message, { type: 'success' });

It will show nice pop up on screen.


 

Friday, May 26, 2017

PHP strtotime() does not work with dd/mm/yyyy Format

Hello,

This is quick blog regarding PHP strototime function. In our recent project we were importing data from CSV where we faced two issues.

1) If we try to import date like 01/05/2016 considering dd/mm/yyyy format, it saves date in database as 2015-01-05

2) If we try to import date like 31/08/2016 considering dd/mm/yyyy format, it saves data in database as 1970-01-01

In short month and day is swiped while saving. So in case of date like 31/08/2016,  31 is assumed as month and there is no such month in calendar so it gave error and returns date like 1970-01-01

This is first time we faced such issue. I was not sure what's the exact issue but I assumed it has something to do with separator. So we tried same dates with  - instead of / and it worked. So to solve this temporary, we had following solution.

$date = '31/08/2016';
$date = str_replace('/', '-', $date);
echo date('Y-m-d', strtotime($date));

So we replace / with - and it worked but solving problem is not enough, we shall go in deep to check why we had this problem so curiously I looked into function documentation of strtotime and found out following.

"Dates in the m/d/y or d-m-y formats are disambiguated by looking at the separator between the various components: if the separator is a slash (/), then the American m/d/y is assumed; whereas if the separator is a dash (-) or a dot (.), then the European d-m-y format is assumed. "

So indeed the problem here was with the separator.

Hope this helps you.