code prettify

Showing posts with label php. Show all posts
Showing posts with label php. Show all posts

Monday, 2 May 2016

PHP best practices going ahead

I have been considering a few things that one needs follow, do and have in their projects and applications and I came up with the below list:

1. Object Oriented Techniques and practices
2. Use of Interface Concept
3. TDD (Test Driven Development) based development both on the server and client side
4. Source code management tool like GIT
5. Language specific package management tool for managing dependencies. For example: Composer for PHP
6. Continuous Integration tool
7. Automated testing

There are many more, I might be missing. Please let me know in comments. :)

Saturday, 13 February 2016

Using git pre-commit hook for php and js syntax check

This is a followup from my two previous posts on php and js git pre-commit syntax check where I had mentioned how to check for php and js syntax independently using pre-commit with git.



But what if we wanted to check for both php and js syntax at same time while committing. So, I used the scripts used for both and combined them. Below is the final result.

#!/bin/bash

commit_error=false

ROOT_DIR="$(pwd)/"
LIST=$(git diff-index --cached --name-only --diff-filter=ACMR HEAD)
ERRORS_BUFFER=""
for file in $LIST
do
    EXTENSION=$(echo "$file" | grep ".php$")
    if [ "$EXTENSION" != "" ]; then
        ERRORS=$(php -l "$ROOT_DIR$file" 2>&1 | grep "Parse error")
        if [ "$ERRORS" != "" ]; then
            if [ "$ERRORS_BUFFER" != "" ]; then
                ERRORS_BUFFER="$ERRORS_BUFFER\n$ERRORS"
            else
                ERRORS_BUFFER="$ERRORS"
            fi
            echo "Syntax errors found in file: $file "
        fi

        # Check for xdebug statments
        ERRORS=$(grep -nH xdebug_ "$ROOT_DIR$file" | \
                 sed -e 's/^/Found XDebug Statment : /')
        if [ "$ERRORS" != "" ]; then
            if [ "$ERRORS_BUFFER" != "" ]; then
                ERRORS_BUFFER="$ERRORS_BUFFER\n$ERRORS"
            else
                ERRORS_BUFFER="$ERRORS"
            fi
        fi
    fi
done
if [ "$ERRORS_BUFFER" != "" ]; then
    echo
    echo "Found PHP parse errors: "
    echo -e $ERRORS_BUFFER
    echo
    echo "PHP parse errors found. Fix errors and commit again."
    commit_error=true
else
    echo "No PHP parse errors found. Committed successfully."
fi

files=$(git diff --cached --name-only --diff-filter=ACM | grep "\.js$")
if [ "$files" = "" ]; then
    exit 0
fi

pass=true

JS_ERRORS_BUFFER=""

echo -e "\nValidating JavaScript:\n"

for file in ${files}; do
    result=$(jslint ${file} | grep "${file} is OK")

    if [ "$result" != "" ]; then
        echo -e "\t\033[32mJSLint Passed: ${file}\033[0m"
    else
        JS_ERRORS=$(jslint ${file})
        JS_ERRORS_BUFFER="$JS_ERRORS_BUFFER\n$JS_ERRORS"
        echo -e "\t\033[31mJSLint Failed: ${file}\033[0m"
        pass=false
    fi
done

echo -e "\nJavaScript validation complete\n"

if ! $pass; then
    echo -e "\033[41mCOMMIT FAILED:\033[0m Your commit contains files that should pass JSLint but do not. Please fix the JSLint errors and try again."
    echo -e $JS_ERRORS_BUFFER
    echo
    commit_error=true
else
    echo -e "\033[42mCOMMIT SUCCEEDED\033[0m\n"
fi

if $commit_error; then
    exit 1
fi

Store it in .git/hooks/pre-commit
Give it execute permission: $ chmod +x .git/hooks/pre-commit and it should be good to go :)

Sample output when I try to commit two php files and two js files with syntax errors:

Filenames with code content:

error.php


<?php
$
array = ;

another_error.php

<?php
var_dump(');

error.js

i =

another_error.js

i = k;

$ git commit -m 'Error Commit' error.php another_error.php error.js another_error.js
Output from above error commit:

Syntax errors found in file: another_error.php 
Syntax errors found in file: error.php 

Found PHP parse errors: 
PHP Parse error: syntax error, unexpected ';' in /var/www/html/error.php on line 2
PHP Parse error: syntax error, unexpected '');' (T_ENCAPSED_AND_WHITESPACE) in /var/www/html/another_error.php on line 2

PHP parse errors found. Fix errors and commit again.

Validating JavaScript:

JSLint Failed: error.js
JSLint Failed: another_error.js

JavaScript validation complete

COMMIT FAILED: Your commit contains files that should pass JSLint but do not. Please fix the JSLint errors and try again.

error.js #1 'i' was used before it was defined. i = // Line 1, Pos 1 #2 Unexpected character '(space)'. i = // Line 1, Pos 4 #3 Unexpected '(end)'. i = // Line 1, Pos 3 #4 Stopping. (50% scanned). // Line 1, Pos 3
another_error.js #1 'i' was used before it was defined. i = k; // Line 1, Pos 1 #2 'k' was used before it was defined. i = k; // Line 1, Pos 5

Above script can be further modified to format the output better but is helpful for basic php and js syntax issues and js standard checks in code :)

Sunday, 7 February 2016

How to generate text representation of an image using PHP?

We will learn how to convert an image to its text representation using PHP that can be used in an html page (if any such requirement arises in your application or just for fun sake :) ).


The steps followed to convert the image to text representation are:

1. Get the width and height of the image to be converted.
2. Loop through every pixel value in the image.
3. At every pixel value, find the color at that position.
4. Apply that color to a # symbol we use to represent that pixel.
5. Finally we get the text representation of the image represented by # (hashes).

Code:

<html>
    <body style="background-color: #000000;">
        <tt>
<?php

$img = imagecreatefromjpeg('red_leaf.jpg');
$dx = imagesx($img);
$dy = imagesy($img);

// Loop through each pixel in the image and check the color
// Then do something with that color data like display the # character
// at the appropriate color for each pixel.
for ($y = 0; $y < $dy; $y++) 
{
     for ($x = 0; $x < $dx; $x++) 
    {
         $col = imagecolorat($im, $x, $y);
         $rgb = imagecolorsforindex($im, $col);
         printf('<font color=#%02x%02x%02x>#</font>',
             $rgb['red'], $rgb['green'], $rgb['blue']);
    }

     echo "<br>\n";
}

imagedestroy($im);

?>
        </tt>
    </body>
</html>

Image used in the program:

Sample output can be seen here.

Cool isn't it :)

Friday, 5 February 2016

Associating git hooks with php syntax check

Many a times we have faced this problem that when we commit something and it breaks something on the server due to some syntax error.
I know that these can be caught by IDEs and good editors, but sometimes there might be an syntax error introduced after a code merge conflict resolution and commit.

To address this, we can use git pre-commit hooks to check for any syntax errors in the to be committed files.

There is a good script I found which does this at https://github.com/ReekenX/phpcheck-git

Steps to add pre-commit php syntax check with git:

(Issue below commands in your console)

1. $ cd /project/directory/

2. $ cd .git/hooks/

3. Get the pre-commit script file from above github page or from direct link: https://raw.githubusercontent.com/ReekenX/phpcheck-git/master/pre-commit

$ wget https://raw.githubusercontent.com/ReekenX/phpcheck-git/master/pre-commit

4. Give execute permission to it.

$ chmod +x pre-commit

This should be it :)

Now if you try to commit any php file, it will display message about any syntax error. If there are, then it will specify the file, error and line number where the error took place and will abort the commit.

This small tool will help us in better checking our code before being committed :)

Sunday, 6 September 2015

Session logout fix with CodeIgniter framework when dealing with ajax requests and iframes in SPA applications

Recently, we had an issue in our application which is a single page application(SPA). We have all the functionality in a single page and most of the data and view changes happen through ajax requests and iframe page displays.
We are using CodeIgniter framework for this application. So sometimes what happened was the user was logged out while accessing the application and this occurred once a while for 1 or 2 users, not a reproducible case one would say.
Before starting on the case, I would like to specify the steps which CodeIgniter takes for checking session for any request.
Steps:
1. Read session cookie sent from browser.
2. Read session cookie process proceeds with below step checks (If any one step fails below, it results in create one session cookie)
2a. Checks if session cookie is present
2b. Checks if it is a valid session cookie by using it's decryption algorithm check
2c. If  valid session, then check if it is expired
2d. Check for config related options if enabled like check ip, check useragent etc.
2e. If database enabled then check session is present in database
3. If a valid cookie is found, then check if it needs update since its last activity update which is determined by below condition, update database if enabled with updated cookie and send the updated cookie (even if not updated in database) to browser.
($this->userdata['last_activity'] + $this->sess_time_to_update) < $this->now
The problem which occurs is related to step 3 when update of session cookie happens.
There are two versions of CodeIgniter I would like to discuss here for step 3:
1. CodeIgniter Version 2.2.0: Session update happens for all requests that is page reloads and ajax requests.
2. CodeIgniter Version 2.2.1 and above: Session update happens only for page reload requests and not for ajax requests.
So for case 1, if the issue would occur if there are many ajax requests happening from browser at same time and for case 2, it would occur if you are making multiple iframe requests at same time from SPA application.
Note this issue happens only if there are simultaneous requests happening related to respective versions as described above and the server detects a session cookie update case. Given that these are the two conditions which need to be satisfied for the issue to occur, it happens sometimes(very rarely).
Request flow and session cookie setting process flow
Explanation:
Let me explain the issue. I will be using the term requests instead of the respective detailed requests for respective CodeIgniter versions.
So lets say in our SPA application, "A" is the session cookie value stored in the browser and two requests R1 and R2 happen at same time (both will have cookie request value "A") and reach the CodeIgniter server at same time.
Note the session value in database is "A" which must match browser cookie one.
Lets say R1 is first processed by the server. So server checks it is a valid cookie and detects that it needs an update. So it generates a random cookie "B" and updates database session where old session is A. So in database, new value is now "B" and then sends updated cookie value to browser. So now the cookie value in browser is updated from "A" to "B".
After that R2 is then being processed by the server. The request still contains the old cookie session value "A" and same old last updated time. So server detects that it needs an update and generates a random session value "C" and tries to update the value in database where old_value is "A", which is not present any where. So the update does not occur, but it nevertheless sends the update cookie data with "C" to the browser. So now the cookie value in browser is updated from "B" to "C".
So now when you make any new request from the SPA application, it will use cookie session value "C" and while trying to read the session from database, it won't find the value in database(since the update had not been done to "C" and the current value in database is "B") and will destroy your session.
Solution:
The main issue here is with the second request R2, which could not update the value in database but sent an updated cookie value to browser which it should not. So this can be solved by checking if any rows were affected in database and then only sent updated cookie session data to browser. So in this case generated random value "C" would not be sent to browser and new requests would use "B" value which is still present in the browser.
Original code in sess_update() function in Session library:

// Update the session ID and last_activity field in the DB if needed
if ($this->sess_use_database === TRUE)
{
    // set cookie explicitly to only have our session data
    $cookie_data = array();
    foreach (array('session_id','ip_address','user_agent','last_activity') as $val)
    {
        $cookie_data[$val] = $this->userdata[$val];
    }

    $this->CI->db->query($this->CI->db->update_string($this->sess_table_name, array('last_activity' => $this->now, 'session_id' => $new_sessid), array('session_id' => $old_sessid)));
}

// Write the cookie
$this->_set_cookie($cookie_data);
Modified fixed code:

// Update the session ID and last_activity field in the DB if needed
if ($this->sess_use_database === TRUE)
{
    // set cookie explicitly to only have our session data
    $cookie_data = array();
    foreach (array('session_id','ip_address','user_agent','last_activity') as $val)
    {
        $cookie_data[$val] = $this->userdata[$val];
    }

    $this->CI->db->query($this->CI->db->update_string($this->sess_table_name, array('last_activity' => $this->now, 'session_id' => $new_sessid), array('session_id' => $old_sessid)));

    if ($this->CI->db->affected_rows())
    {
        // Write the cookie
        $this->_set_cookie($cookie_data);
    }
}
else
{
    // Write the cookie
    $this->_set_cookie($cookie_data);
}
This finally fixed the issue. Hope it helps :)