Deals

Sunday, April 24, 2016

Solve Magento Error MySQL: Can't create/write to file '/tmp/#sql_3c6_0.MYI'

Recently one our client called me and said Magento Site is not working so I checked the site and found following error.

MySQL: Can't create/write to file '/tmp/#sql_3c6_0.MYI'

So what's the meaning of this error. At first it looks like a permission issue that tmp folder does not have necessary permissions. I checked through SSH and permission was ok. But still it's not working. 

Second issues could be tmp folder owner is not web root, hence it's not allowing to create files from web users. I checked that also and owner was correct. 

After few checks through SSH, I found out that it was actually an issue of Inodes on server. Disk was almost full and there were no enough space to create new files. So have to delete some files to create space. 

This you can do through SSH, but make sure you what are the files you are deleting and will that create any issues. If you don't know much about magento files and folders, PLEASE CONTACT YOUR HOSTING PROVIDER to delete it for you.

In my case I deleted old backups of database and deleted magento caches and sessions files from /var folder and then my site was up and working normally. 

Hope this helps you.

Laravel 5.x Dispaly Custom Error Page on Exception and Error

In this quick and small blog I am going to explain how to create custom error page for your Laravel 5.x project.

Laravel 5.x have custom exception handler class which you will find in app/Exceptions/Handler.php

If you open this file, you will see below code.

/**
* Render an exception into an HTTP response.
*
* @param  \Illuminate\Http\Request  $request
* @param  \Exception  $e
* @return \Illuminate\Http\Response
*/
public function render($request, Exception $e)
{
return parent::render($request, $e);
}

This code renders exceptions on your HTTP response and your end users will actually see following pages.


That's really embarrassing for your end users as they don't understand what is this all about. So best practice is to hide this types of errors and show custom error page to users. For that add a error page view in your project and render it on exception. Modify above function as follow.

/**
     * Render an exception into an HTTP response.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Exception  $e
     * @return \Illuminate\Http\Response
     */
    public function render($request, Exception $e)
    {

        return response()->view('errors.index');
    } 

That's it and now you will have custom error page in your laravel app.

Laravel Swagger Integration for API and Code Documentation

I know, I know, all developers hate documentation. Even I also don't like it but it's an industry practice and we have to follow this. In this blog I am going to explain how you can integrate swagger most popular framework for API with Laravel for creating API docs. Swagger is an incredible way to easily document and test your APIs. So here is the step by step guides.

1) Go to your laravel project on Terminal and include Swagger PHP package with composer.

composer require zircote/swagger-php

This will install swagger php package to laravel and will update your vendor folder. Now we have to create documentation.

2) There is standard syntax for creating docs with swagger. For each API functions and classes you have to add swagger config and config have all the standard keys to define what kind of information you will include in docs. You can check this on following URL.


Hover mouse on left side object and it will give you information on right side.


This you have to add in add in your controllers and models in your laravel project. So lets define some basic info. For example see following swagger config we have added. This we have added a comments to top of the controller function.

@SWG\Swagger(
     *     basePath="",
     *     schemes={"http"},
     *     @SWG\Info(
     *         version="1.0",
     *         title="Sample API",
     *         @SWG\Contact(name="Hiren Dave", email="hdave10@gmail.com"),
     *     ),
     *   @SWG\Get(
     *     path="/",
     *     description="Returns basic information",
     *     produces={"application/json"},
     *     @SWG\Response(
     *         response=200,
     *         description="Application Overview"
     *     )
     *   )
     * )

And following is my API function.

        public function index()
{
              return Response::json(array('success'=>false,'message'=>'This is Basic Info of API'));
}

It have basic info like API info and API path and output information.

3) Build Swagger Docs.

Go to your laravel project in terminal and run following command.

./vendor/bin/swagger ./app/Http

It will generate swagger.json file in your root folder with all the swagger config you have added in your controller. 

4) Add swagger UI to project to show this docs.

Go to following link to download swagger UI.


Download it and copy all the files from dist folder to your public/docs folder. Now open public/docs/index.html page and update path of your swagger.json file in following code.

if (url && url.length > 1) {
        url = decodeURIComponent(url[1]);
      } else {
        url = "http://petstore.swagger.io/v2/swagger.json";
      }

Change URL to url your own swagger.json URL, for example in my case it was http://localhost/laravel-swagger/swagger.json

5) Read the Docs. Now go to public docs folder. In my case URL was

http://localhost/laravel-swagger/public/docs/index.html

When you run, you will see following output page.


That's it and you have your API docs minimum efforts. Hope this helps you.

Wednesday, April 20, 2016

Laravel Add Date Text in PNG and JPEG Image

In our recent project we have a requirement to add date as text in all the uploaded image. For example, check below image.


In this blog I am going to explain how you can do this.

First of open image from the path.

$publicPath = public_path();
$imagePath = $publicPath."/image/myImage.png"; //replace it with your own path

Create a date text.

$text = date('d-m-Y');

Setup font

$font = $publicPath."/fonts/RobotoCondensed-Bold.ttf"; //replace it with your own path

Now while working on this I faced two issues

1) PHP GD functions like imagecreatefrompng was not woking.
2) PNG image was having JPEG mime type.

To resolve first issue, first check your phpinfo(). It should have PNG support enabled.


If it's not enabled, enable it.

To solve second issue check mime type of image with file info function and use respective function to get image resources.

$finfo = finfo_open(FILEINFO_MIME_TYPE);
$mime = finfo_file($finfo, $imagePath);

$image = null;
     
if($mime == "image/png"){

            $image = imagecreatefrompng($imagePath);
        
}else{

            $image = imagecreatefromjpeg($imagePath);       
}

Now we have image resource, we have to add text in image and save image.

$black = imagecolorallocate($image, 0, 0, 0);
imagettftext($image, 20, -45, 600, 20, $black, $font, $text);
imagepng($image,$imagePath);
imagedestroy($image);

That's it. Please note in my case all the images were of fixed width and height so I gave fix X = 600 and y = 20 coordinate for text. If you have variable width and height calculate it dynamically.

Hope this helps you.

Thursday, April 14, 2016

Laravel Share Some Variable with All Views

Hello,

Recently in one of my laravel project we have a requirement create side menu in app with some dynamic stats numbers like

Users   (12)
Managers  (10)
Questions  (25)

This menu is included in all the views and to set dynamic values in that we have to share this numbers globally. In this blog I am going to mention how to so this.

1) Create a BaseController class and extend it with controller and add a constructor.

class BaseController extends Controller {
       public function __construct() {
     
       }
}

2) Inside that constructor get all the numbers and share it with view

$users = DB::table('users')->count();
$managers = DB::table('managers')->count();
$questions = DB::table('questions')->count();

View::share('users',$users);
View::share('managers',$managers);
View::share('questions',$questions);

after adding this code your base controller should look like following.

class BaseController extends Controller {
       public function __construct() {
             $users = DB::table('users')->count();
             $managers = DB::table('managers')->count();
             $questions = DB::table('questions')->count();

            View::share('users',$users);
            View::share('managers',$managers);
            View::share('questions',$questions);
       }
}


3) Now extend this base controller to all other controllers.

class MyConttoller extends BaseController {

}

That's it now any view which you render from controller will have those variables by default. Now you just have to use those variables in views.

<ul>
       <li> Users  ({{$users}}) <li/>
       <li> Managers  ({{$managers}}) <li/>
       <li> Questions  ({{$questions}}) <li/>
<ul/>

Hope this helps you.


Saturday, March 26, 2016

Sencha Touch 2.2 Scrolling Issue in Android 5.1

Hello,

If your application is created with Sencha Touch 2.2 it must be having scroll issue for forms, list and carousels in android 5.1 on words.

The reason is some chrome updates have broken Sencha Touch scrolling logic and that's why it's not working so what is the solution, well the simple solution is to update your sencha touch version in the app. But what if the app is not created with Sencha CMD. Yes in my case previous developer have created app with loading sencha-touch-all,js and css. So I can not simply modify it with new version y sencha cmd and there were lots of CSS overrides. So what to do. In this blog I am going to explain.

First of all create folder with name util in your app folder. Now create new JS file in util folder and name it "PaintMonitor.js" and add following code to it.

/**
 * Created by hirendave on 3/7/16.
 */
Ext.define('SEOshop.util.PaintMonitor', {
    override: 'Ext.util.PaintMonitor',

    uses: [
        'Ext.env.Browser',
        'Ext.env.OS',
        'Ext.util.paintmonitor.CssAnimation',
        'Ext.util.paintmonitor.OverflowChange'
    ],

    constructor: function(config) {
        return new Ext.util.paintmonitor.CssAnimation(config);
    }

}, function () {
    //
    console.info("Ext.util.PaintMonitor temp. fix is active");
    //
});

Crete one more file with name "SizeMonitor.js" and add following code to it.

/**
 * Created by hirendave on 3/7/16.
 */
Ext.define('SEOshop.util.SizeMonitor', {
    override: 'Ext.util.SizeMonitor',

    uses: [
        'Ext.env.Browser',
        'Ext.util.sizemonitor.Default',
        'Ext.util.sizemonitor.Scroll',
        'Ext.util.sizemonitor.OverflowChange'
    ],
    constructor: function (config) {
        var namespace = Ext.util.sizemonitor;

        if (Ext.browser.is.Firefox) {
            return new namespace.OverflowChange(config);
        } else if (Ext.browser.is.WebKit) {
            if (!Ext.browser.is.Silk && Ext.browser.engineVersion.gtEq('535') && !Ext.browser.engineVersion.ltEq('537.36')) {
                return new namespace.OverflowChange(config);
            } else {
                return new namespace.Scroll(config);
            }
        } else if (Ext.browser.is.IE11) {
            return new namespace.Scroll(config);
        } else {
            return new namespace.Scroll(config);
        }
    }
}, function () {
    //
    console.info("Ext.util.SizeMonitor temp. fix is active");
    //
});

Now go to your app.js file and add following code to your application object.

requires: [
        'YOUR_APP.util.SizeMonitor',
        'YOUR_APP.util.PaintMonitor'
    ]

That's it and it should solve all the scrolling and rendering issue in Android 5.1 and above version.

Hope this helps you.

Laravel LinkedIn Verification - Laravel LinkedIn Login

Recently in one of the laravel project we have to add LinkedIn verification. It's like we have to auto check if user is signing up on our app should have LinkedIn profile with same name and email. In this blog I am going to explain how to do this. First of all we will need one LinkedIn application. Go to following URL to create new LinkedIn application.

https://www.linkedin.com/developer/apps/

Once you create application it should look like below screenshot.


Now you have to copy client Id and client secret to your laravel app, that you can do in env file.

LINKEDIN_CLIENT_ID = your_client_id
LINKEDIN_CLIENT_SECRET = your_client_secret

Now in your laravel view you have to add a link, so user can click on it and go to LinkedIn for authentication.

Add following to your routes.

    Route::get('/user/linkedin-verification','AdminController@viewLinkedinVerification');

Following should be function of your controller.

        $user_id = Auth::user()->id;
        $user = User::find($user_id);
        $redirect_uri = env('LINKEDIN_REDIRECT_URL', '');
        $client_id = env('LINKEDIN_CLIENT_ID', '');
        $client_secret = env('LINKEDIN_CLIENT_SECRETE', '');
        return view('linkedinverification.index')-              >with(['user'=>$user,'redirect_uri'=>$redirect_uri,'client_id'=>$client_id,'client_secret'=>$client_secret]);

Where user is currently logged in user and redirect URL is the URL that will be invoked on successful LinkedIn verification,

Your view should have a link like below.

                        <p>Please verify your LinkedIn account. <a href="https://www.linkedin.com/uas/oauth2/authorization?response_type=code&client_id={{$client_id}}&redirect_uri={{$redirect_uri}}&state=ab234aatdssda">Click Here</a></p>

When user click on this link they will see below screen of your LinkedIn application.


Once you are logged in with your LinkedIn account it will redirect back you website with specified redirect url with access code.

Add following to your laravel route.

Route::get('/user-dashboard/linkedin-response','AdminController@linkedinVerification');

In my case I used above URL, you can have different URL as per your requirement.

Now in linkedinVerification function first we will get access code which is generated by LinkedIn and get oAuth access token first. following is the code to get access token.

            $redirect_uri = env('LINKEDIN_REDIRECT_URL', '');
            $client_id = env('LINKEDIN_CLIENT_ID', '');
            $client_secret = env('LINKEDIN_CLIENT_SECRET', '');

            $code = Input::get('code');
            
            /// for get accesstoken
            $ch = curl_init();
            curl_setopt($ch, CURLOPT_URL,"https://www.linkedin.com/uas/oauth2/accessToken");
            curl_setopt($ch, CURLOPT_POST, 5); // number of post parameters
            curl_setopt($ch, CURLOPT_POSTFIELDS,
                        "code=".$code."&client_id=".$client_id."&redirect_uri=".$redirect_uri."&grant_type=authorization_code&client_secret=".$client_secret);
            
            // receive server response ...
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
            
            $server_output = curl_exec ($ch);
            curl_close ($ch);

Now you get access token, use that to get user profile information.

                $result = json_decode($server_output, true);
                
                $access_token = $result['access_token'];
                
                if($access_token != '')
                {
                    // for get customer email
                    $datach = curl_init();  
                    $authorization = 'Authorization: Bearer '.$access_token;
                    curl_setopt($datach,CURLOPT_URL,'https://api.linkedin.com/v1/people/~:(id,email-address,first-name,last-name)?format=json');
                    curl_setopt($datach,CURLOPT_RETURNTRANSFER,true);
                    curl_setopt($datach, CURLOPT_HTTPHEADER, array($authorization));
                 
                    $output=curl_exec($datach);
                 
                    curl_close($datach);
              }

Above call will give you basic user profile, now we just get email and name from it and compare it with credentials registered with us.

Hope this helps you.