Showing posts with label PHP Framework. Show all posts
Showing posts with label PHP Framework. 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

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

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 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.

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.

Monday, April 3, 2017

Beginning Laravel Video Course

Here is something unusual I did apart from programming. My first ever video course "Beginning Laravel" with Packt Publishing



In this course you will learn about basics of Laravel Development. First section is about installation of Laravel. This section will start with introduction of Laravel and installation of Laravel in Mac, Windows and Linux. Then we will cover, basics of Laravel including, understanding of Framework Structure, basics of Artisan Commands, Composer, Core Concepts of Laravel, MVC structure, Database Migrations, Laravel Controllers, Models and Views etc. In last section
We will finish this course by creating simple Web application with Laravel which will have CRUD operations and basic validations in final section, this will help you getting started with Laravel Development. If you are interested in learning Laravel then this is the course you are looking for. You can buy it at following link.


Beginning Laravel Video Course



Hope you will like this course. Let me know your feedback in comments.

Thursday, March 30, 2017

PHP Debugging - Look for Case Sensitivity In Variable, File Names and Class Names

This blog is coming out of conversation with one of the developer in my team. He recently made some changes in API in local development and push code to test server. But on server it was throwing an error and API was not working. So after trying hard for sometime he came to me and asked for help. He showed me lines of code he has added and as an experienced person I immediately caught his error. The problem was, he declared variable in lowercase and was using variable with uppercase in next line and that's what breaking on server. Something like this

$var = new Class();
$VAR->prop = value;

Case sensitivity is one of the major reason for errors while you are working on local development environment with XAMPP, WAMP in Windows. At this time case sensitive is not applied and it will  treat

$var;
$VAR;
$Var;

as one and the same variables. But when you are working on server, you have unix / linux operating systems like Ubuntu, Fedora etc. At this time case sensitivity is applied and

$var;
$VAR;
$Var;

Are treated as three different variables. So by mistake if you declare it with lower case and try to use it upper case, it will give you an error. So if you are facing this issue that, code works on your local machine, but does not work on server look for the case sensitivity.

Same goes for the filenames and class names. If you have adde file with name

Myclass.php

and if you include it with

include 'MyClass.php';
require 'MyClass.php';

Then it will not be able to find file and it will throw warning or fatal error if you are using require. So make sure that you maintain case sensitivity while naming your class, variables and files in PHP because ultimately your code will be pushed to UNIX / LINUX server and it is case sensitive. 

Monday, March 6, 2017

PHP file_get_contents throws 400 Bad Request Error - Google Geocode API

Recently I was using Google Maps API to geocode address with PHP. There were thousands of addresses in CSV and I have to read it one by one and do geocode it and get lat long and other missing info of the address. So I was using file_get_contents function to fire HTTP request and get output like this.

$geocode = file_get_contents('https://maps.google.com/maps/api/geocode/json?address='.urlencode($records[0]).'&key=API_KEY&sensor=false');
$output = json_decode($geocode);

It worked for few address but for some addresses it throws error.

ErrorException in Controller.php line 535:
file_get_contents(URL): failed to open stream: HTTP request failed! HTTP/1.0 400 Bad Request

That's because some of the addresses in the CSV were not properly formatted and there were some special characters in it as addresses were copied from web pages. But the problem was it's eventually breaking the execution of the script. So to fix it use PHP curl instead of file_get_contents. As it does not throw exception on bad request but it gives you response code and that you can check before you get output. So here is my code.

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'https://maps.google.com/maps/api/geocode/json?address='.urlencode($records[0]).'&key=APIKEY&sensor=false');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$geocode = curl_exec($ch);

if(curl_getinfo($ch, CURLINFO_HTTP_CODE) === 200) {
        // convert response
        $output = json_decode($geocode);
if($output->status == 'OK'){

}
}
curl_close($ch);

So as you can see on above code, we are using checking CURLINFO_HTTP_CODE, if it's 200 that means HTTP request is successfully executed or in case there is a bad request you can check it and skip accessing the output. So it won't throw an error.

Friday, December 30, 2016

PHP / MySql - Generate Big Reports from Big Data

Big data is a term that describes the large volume of data – both structured and unstructured – that inundates a business on a day-to-day basis. But it’s not the amount of data that’s important. It’s what organizations do with the data that matters. Big data as a service market to grow in near future. “Big Data” analysis is a hot and highly valuable skill now a days. For the big data analysis, an organization needs reports generated from it and to generate reports from big data we need some spacial tricks. In this blog I am going to explain some best practices to generate big reports from big data in PHP / MySql.

Challenges we face in managing Big Data with MySql


In MySql when we have big data we face certain performance issues. Most crucial issue is slow performance of MySql. When you have millions of rows in table and you want to search certain raws from it, it will take some time to get data and you need to improve in that. So in MySql there is a way to make faster data retrieval.

INDEXING


Yes, that 's right indexing solved my issue. There was a table in my database which has 100K records and executing query from it was taking lots of time as there was no indexing. So I created an index on columns which are used mostly for querying that table and after creating index query was working blazing fast.

If you are facing the same issue, better check your database queries and optimize it with indexing to make it faster.

Challenges we face in generating Big Reports with PHP


In PHP when we generate big reports it will surely take time and while working with PHP we have certain restrictions. For example, a PHP script can run for only certain time limits on any server and that limits can not be changed on most of server providers. So in case of generating big reports we surely need time as we have lots of data at backend and from it we are creating reports. So how to deal with it. 

Here is the one solution I always use. You can make use of scheduled cron job. Cron jobs run in background and there is no time restrictions with it so it can run for any amount of time and it can resources as much as possible. So get the reports parameters from the user and save it in database and schedule it for certain time.  For example user want to see day wise sales of products for a month. Save parameters like month in database have a scheduled cron job to read this data and start creating reports in background. Once the report is generated you can notify user about it so they can download it. Which this trick you can generated Big Reports from Big Data.