Facebook

Sunday, January 31, 2016


Web config file - alternative of htaccess in windows machine
<?xml version="1.0" encoding="UTF-8"?> <configuration>
    <system.webServer>
        <rewrite>
            <rules>
                <rule name="Clean URL" stopProcessing="true">

                <match url="^news/(.*).html" />
                <action type="Rewrite" url="/newssingle.php?url={R:1}" appendQueryString="true" />

                </rule>
                <rule name="Clean URL 1" stopProcessing="true">

                <match url="^index.html" />
                <action type="Rewrite" url="index.php" appendQueryString="true" />

                </rule>
                <rule name="Clean URL 2" stopProcessing="true">

                <match url="^newsevents.html" />
                <action type="Rewrite" url="newsevents.php" appendQueryString="true" />

                </rule>
                <rule name="Clean URL 3" stopProcessing="true">

                <match url="^contactus.html" />
                <action type="Rewrite" url="contactus.php" appendQueryString="true" />

                </rule>
                <rule name="Clean URL 4" stopProcessing="true">

                <match url="^services.html" />
                <action type="Rewrite" url="services.php" appendQueryString="true" />

                </rule>
                <rule name="Clean URL 5" stopProcessing="true">

                <match url="^aboutus.html" />
                <action type="Rewrite" url="aboutus.php" appendQueryString="true" />

                </rule>
            </rules>
        </rewrite>
    </system.webServer>
</configuration>

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <system.webServer>
        <rewrite>
            <rules>
                <rule name="Clean URL" stopProcessing="true">
                    <match url="^(.*).html" />
                    <action type="Rewrite" url="/pages.php?page_slug={R:1}" appendQueryString="true" />
                </rule>
            </rules>
        </rewrite>
    </system.webServer>
</configuration>

Wednesday, January 6, 2016

Responsive design: Tips and tricks


1. Usage: Make colorbox responsive.

$(document).ready(function() {
    $(".ajax-popup").colorbox({width: "90%",maxWidth: "900px", maxHeight:'90%'});
})

1. Usage: JQuery ui date picker limit date range.

$(document).ready(function() {
    $( "#datePicker" ).datepicker({
        maxDate: "+1M +10D -15Y",
        minDate: -20
    })
})

Saturday, January 2, 2016

Function to render text as image - escape spam bots


Escaping contact information from spam bots is one of the major challenges developers facing. Converting the text to image and rendering as image is one basic solution. Here is a function I use.
Function to render text as image
<img src="<?php echo render_text_image('test image', 183, 50);?>" />


function render_text_image($string, $width, $height, $text_align_pos = 0)
{


    $img = imagecreatetruecolor($width, $height);

    $imageX = imagesx($img);
    $imageY = imagesy($img);

    imagealphablending($img, false);
    imagesavealpha($img, true);

    $transparent = imagecolorallocatealpha($img, 255,255,255, 127);
    $white = imagecolorallocate($img, 129, 78, 16);
    $black = imagecolorallocate($img, 0, 0, 0);
    $grey = imagecolorallocate($img, 127,127,127);
    //imagefilledrectangle($img, 0, 0, $imageX, $imageY, $grey);
    imagefilledrectangle($img, 0, 0, $imageX, $imageY, $transparent);

    $font = ROOT_DIRECTORY . "assets/font/arialbd.ttf";
    //$font = ROOT_DIRECTORY . "assets/font/arialbd.ttf";
    $fontSize = 12;
    $text = $string;

    $textDim = imagettfbbox($fontSize, 0, $font, $text);
    $textX = $textDim[2] - $textDim[0];
    $textY = $textDim[7] - $textDim[1];

    $text_posX = ($text_align_pos== "center") ? ($imageX / 2) - ($textX / 2) : $text_align_pos;
    $text_posY = ($imageY / 2) - ($textY / 2);

    imagealphablending($img, true);
    imagettftext($img, $fontSize, 0, $text_posX, $text_posY, $white, $font, $text);
    //ImageString($img,2,0,0, $text,$black);
    //Get image to a variable
    ob_start();
    imagepng($img);
    // Capture the output
    $imagedata = ob_get_contents();
    // Clear the output buffer
    ob_end_clean();

    return "data:image/png;base64," . base64_encode($imagedata);
}

Monday, December 28, 2015

Function to generate clean url slugs from string with duplication check


Function to generate clean url slugs from string with duplication check


function generateClassifiedSlug($string, $id=0){
    //Set char set to UTF-8 - to manage accented characters
    setlocale(LC_ALL, "en_US.UTF8");
    //Remove everything except alphabets and digits
    $url_string=preg_replace("/[^a-z0-9]/i"," ", ltrim(rtrim(strtolower($string))));
    //Remove multiple spaces
    $url_string = preg_replace("/\s+/", " ", $url_string);
    //Replace space with dashes
    $newurl_string=str_replace(" ","-",$url_string);
    //Condition for add / update
    if(!empty($id) && $id!=0){
        $condition = "BlogId!='".$id."' AND ";
    }else{
        $condition ="";
    }
    $queryCount = 'SELECT blog_url from tblblogs WHERE '.$condition.'
                    blog_url LIKE "'.$newurl_string.'"';

    //Check duplicate
    $rqC = mysql_num_rows(mysql_query($queryCount));
    $i=0;
    while($rqC != 0) {
        $i++;
        //Add number to avoid duplicate
        $newurl_string = $newurl_string."-".$i;
        $queryCount = 'SELECT blog_url from tblblogs WHERE '.$condition.'
                    blog_url LIKE "'.$newurl_string.'-'.$i.'"';
        $rqC = mysql_num_rows(mysql_query($queryCount));
    }

    $newurl_string = $newurl_string.(!empty($i) ? "-".$i : "");

    return $newurl_string;
}

Sunday, December 6, 2015

php file upload: clean name of uploaded file, check for duplicate


File upload: clean name of uploaded file, check for duplicate
$config['upload_path'] = DIR_UPLOAD_BANNER;

$file_parts = pathinfo($_FILES['cms_banner_image']['name']);

//Clean file name, replace all specialcharacters with dahs "-" $file_name = preg_replace('/[^A-Za-z0-9\-]/', '', $file_parts['filename']);

//Replace multiple dash with single $file_name = preg_replace('/-+/', '-', $file_name); $config['file_name'] = $file_name.'.'.$file_parts['extension'];

//Check for duplicate file names $counter = 0;
while (file_exists($config['upload_path'].$config['file_name'])) {
    $counter++;
    $config['file_name'] = $file_name.'_'.
                           $counter.'.'.
                           $file_parts['extension'];
}

Wednesday, November 18, 2015

Maps - enable scroll after first click on map only

Complete script for google map that will enable zoom on clicking in the map area only



<script type='text javascript' src="https://maps.googleapis.com/maps/api/js?key=&sensor=false&extension=.js">
<script type='text javascript'="">
    jQuery(document).ready(function(){
        var latitude = $('#map_latitude').val();
        var longitude = $('#map_longitude').val();
        // When the window has finished loading create our google map below
        google.maps.event.addDomListener(window, 'load', init);
        function init() {
            // Basic options for a simple Google Map
            // For more options see: https://developers.google.com/maps/documentation/javascript/reference#MapOptions
            var mapOptions = {
                // How zoomed in you want the map to start at (always required)
                zoom: 14,
                // The latitude and longitude to center the map (always required)
                center: new google.maps.LatLng(latitude,longitude),
                //Disable scroll wheel by default,
                scrollwheel: false,
                // How you would like to style the map.
                // This is where you would paste any style found on Snazzy Maps.
            // Get the HTML DOM element that will contain your map
            // We are using a div with id='map' seen below in the 
            var mapElement = document.getElementById('map');
            // Create the Google Map using out element and options defined above
            var map = new google.maps.Map(mapElement, mapOptions);
            var marker = new google.maps.Marker({

                map: map,

                position: map.getCenter(),

                icon: 'images/google-map-cion.png'

            });
            // Listen to click event on map and enable zoom
            map.addListener('click', function() {
                map.set('scrollwheel', true);
            });


        }
    })
    

</script>

DEMO

Wednesday, November 11, 2015

Simple Ajax Pagination Script on Scroll Down


Credit: Jaspreet Singh

<script type="text/javascript">
    jQuery(document).ready(function($) {
    //Set current page to 1     var count = 1;
    $(window).scroll(function(){
          if  ($(window).scrollTop() == $(document).height() - $(window).height()){
             //Load artices of current page              loadArticle(count);
             //Increment current page after loading              count++;
          }
    });

    function loadArticle(pageNumber){
          //Show loader           $(".sk-circle").removeClass("hideme");
          //Get search string           var search_string = $("#search_name").val();
          $.ajax({
              url: "ajaxsearch.php",
              type:"POST",
              data: "search_string="+search_string+"&page_no="+ pageNumber,
              success: function(html){
                  //Hide loader                   $(".sk-circle").addClass("hideme");
                   if(html == "error"){

                    } else {
                        $("#search_list").append(html);
                    }
                      // This will be the div where our content will be loaded
              }
          });
      return false;
    }

    });

</script>

Server side code
$search_string = $_POST['search_string'];
$perpage = 10;
$limit = $pages*$perpage;
$search = 'SELECT * FROM `table_name` WHERE `description` like '%$search_string%' or `PartNo` like '%$search_string%' and status='1' order by id ASC limit $limit, $perpage';

Thursday, November 5, 2015

PHP Tips and Tricks - Handy


1. ini_set('memory_limit', '-1');
Usage: To temporarily set memory limit to unlimited

2. ini_set('memory_limit', '512M');
Usage: How to temporarily set memory limit to 512MB

3. set_time_limit(0);

4. ini_set('max_execution_time', 0);
Usage: How to temporarily set max execution time to infinite

5. error_reporting(E_ALL);
Usage: Report all PHP errors

6. error_reporting(0);
Usage: Turn off all error reporting

7. ini_set("display_errors", 1);
Usage: Run-time configuration

8.
function getClientIp()
{
    $ip = '';
    if (!empty($_SERVER['HTTP_CLIENT_IP'])) {
        $ip = $_SERVER['HTTP_CLIENT_IP'];
    } elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
        $ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
    } else {
        $ip = $_SERVER['REMOTE_ADDR'];
    }

    return $ip;
}
Usage: Get user ip

/*
 *9.Generate accented seo friendly url
 */

function accented_seo_url($str) {
    mb_internal_encoding('UTF-8');
    $str = utf8_encode($str);

    $new_string = preg_replace('~[^\\pL\d]+~u', "-", ltrim(rtrim(($str))));

    return mb_strtolower($new_string);
}
Usage: Generate accented seo friendly url

10. header('Content-Type: text/html; charset=utf-8');
Usage: Set utf8 in header

11.
/*
* Get 2nd monday of the month
*/

//First monday of the month
$dt = new DateTime('first Monday of jan 2017');

//Second monday of the month
$interval = new DateInterval('P1W');
$next_week = $dt->add($interval);
echo $next_week->format('Y-m-d');
Usage: Get 2nd monday of the month. Example https://eval.in/716901
12.
/*
* Get 3rd tuesday of the month
*/

//First tuesday of the month
$dt = new DateTime('first Tuesday of jan 2017');

//Third Tuesday of the month
$interval = new DateInterval('P2W');
$next_week = $dt->add($interval);
echo $next_week->format('Y-m-d');
Usage: Get 3rd Tuesday of the month. Example https://eval.in/716901

Monday, October 26, 2015

PHPAutomatedDbBackup

Credits: David Walsh for his db backup script. http://davidwalsh.name/backup-mysql-database-php

I implemented a script that can be run via cron, and can schedule different time for backing up diffrent databases.
It reads details of databases scheduled to back up at the toime of execution and create backup
You can schedule the backup of different databases at different time.
The time precision check for minutes only

How to setu-up

Move the code to your server under a directory say "DB_Backup"
Create a database, and a table with this structure

CREATE TABLE IF NOT EXISTS `table_credentials` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `title` varchar(255) NOT NULL,
  `host` varchar(255) NOT NULL DEFAULT 'localhost',
  `db_name` varchar(255) NOT NULL,
  `user_name` varchar(255) NOT NULL,
  `password` varchar(255) NOT NULL,
  `scheduled_execution_time` time NOT NULL,
  `created_date_time` datetime NOT NULL,
  `updated_date_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  `execution_status` enum('0','1','2','3') NOT NULL DEFAULT '0',
  `last_execution_date` datetime NOT NULL,
  `created_ip` varchar(50) NOT NULL,
  `updated_ip` varchar(50) NOT NULL,
  `is_active` enum('0','1') NOT NULL DEFAULT '1',
  `is_mannual` enum('0','1') NOT NULL DEFAULT '1',
  PRIMARY KEY (`id`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;

Now update config.php with your db username, password etc.

Add the credentials of databases you want to backup
If you want to backup 5 databases at 12:00 am and 5 other at 1:00 am the make the value of scheduled_execution_time '12:00:00' for the first 5 databases and '1:00:00' for the next 5 databases.

Now schedule the cron to to execute

ROOT_DIRECTORY/DB_Backup/backup_db.php at 12:00 and 1:00

Thats it.

Any suggestion, updates and modification is welcome

Friday, September 11, 2015

CSS -classes in template

seperator-dash code-hint-inline hint-span validationError demobox htmlbox scriptbox titlebox

Wednesday, September 9, 2015

Complete script for login with google and fetch details of users

Complete script for login with google and fetch details of users

HTML
<a id="customBtn" class="gmail_a"> 
    <img src="<?php echo ROOT_URL_BASE;?>image/google.png" /></a>
</a>

Javascript

var googleUser = {};
//Replace with your google client id
var clientId = 'xx-xx.apps.googleusercontent.com';
var startApp = function() {
    gapi.load('auth2', function(){
        //Retrieve the singleton for the GoogleAuth library
        // and set up the client.
        auth2 = gapi.auth2.init({
            client_id: clientId,
            cookiepolicy: 'single_host_origin',
            // Request scopes
            scope: 'https://www.googleapis.com/auth/plus.login https://www.googleapis.com/auth/userinfo.email'
        });
        attachSignin(document.getElementById('customBtn'));
    });
};

function attachSignin(element) {
    console.log(element.id);
    auth2.attachClickHandler(element, {}, function(googleUser) {
        gapi.client.load('plus', 'v1', signedIn);
    }, function(error) {
        alert(JSON.stringify(error, undefined, 2));
    });
}

function signedIn(){
    gapi.client.plus.people.get({userId: 'me'}).execute(function(resp){
        handleEmailResponse(resp);
    })
}

function handleEmailResponse(resp) {
    var primaryEmail;
    for (var i=0; i < resp.emails.length; i++) {
        if (resp.emails[i].type === 'account') 
            primaryEmail = resp.emails[i].value;
    }
    parseGoogleUserDetails(resp);
}

function parseGoogleUserDetails(GoogleResponse) {
    console.log(GoogleResponse);
    //The response contains many information of users
    var primaryEmail;
    for (var i=0; i < GoogleResponse.emails.length; i++) {
        if (GoogleResponse.emails[i].type === 'account') 
        primaryEmail = GoogleResponse.emails[i].value;
    }
    var first_name = GoogleResponse.name.givenName;
    var last_name = GoogleResponse.name.familyName;
    var gender;
    if (typeof GoogleResponse.gender != 'undefined') {
        gender = capitalizeFirstLetter(GoogleResponse.gender)
    }
    var city;
    if (GoogleResponse.placesLived.length > 0 )
    for (var i=0; i < GoogleResponse.placesLived.length; i++) {
        if (typeof GoogleResponse.placesLived[i].primary){
            if (GoogleResponse.placesLived[i].primary === true) 
                city = GoogleResponse.placesLived[i].value;
        }
    }
    var formData = {
        'socialMedia': 'google',
        'socialMediaId' : GoogleResponse.id,
        'email' : primaryEmail,
        'first_name' : first_name,
        'last_name' : last_name,
        'gender' : gender,
        'city' : city
    };
    createSocialAccount(formData)
}

Tuesday, September 8, 2015

Facebook API

How to get user email and birthday from Facebook API Version v2.4
I found answer in this thread of stack overflow: http://stackoverflow.com/questions/31554854/how-to-get-user-email-and-birthday-from-facebook-api-version-v2-4
This was the answer I get the solution from: http://stackoverflow.com/a/31556390/345721

Monday, September 7, 2015

Mysql tips and tricks

User records table: How to get all ids of peoples who have matching year and month only


First thing you have to achieve is to
"get all date and month of 'dob' column"
This can be achieved by grouping rows based on date_month extracted using the format construct.
SELECT 
DATE_FORMAT(dob, '%m-%d') AS date_month 
FROM bday 
GROUP BY DATE_FORMAT(dob, '%m-%d');
As per your question, Next is
"peoples who have matching year and month only"
ie, group the above results with condition having more than one row. This can be achieved by adding the condition "HAVING count(id) > 1"
Now the query becomes
SELECT 
DATE_FORMAT(dob, '%m-%d') AS date_month 
FROM bday 
GROUP BY DATE_FORMAT(dob, '%m-%d') 
HAVING count(id) >1);
This query returns all date_month where more than one person's dob falls.
Now your ultimate aim is to get
" id of those peoples who have matching year and month only "
This can be achieved by wrapping this results in a sub query. ie, you have to fetch all ids with date and month falls in the set of results extracted using the previous query
SELECT 
id, DATE_FORMAT(dob, '%m-%d') AS date_month
FROM bday
WHERE 
DATE_FORMAT(dob, '%m-%d') IN 
(
    SELECT 
    DATE_FORMAT(dob, '%m-%d') AS date_month 
    FROM bday 
    GROUP BY DATE_FORMAT(dob, '%m-%d') 
    HAVING count(id) >1) ;
)
My table structure:






Content of table:
Query and result:










MySql "CONCAT" usage example

$sql = "SELECT
        email,
        username,
        CONCAT('https://mysiteurl/profile/',user_id) as profile_url
        FROM `engine4_user`
        LIMIT 5000
        into outfile '$path' FIELDS TERMINATED BY ','  LINES TERMINATED BY '\n' ";


mysql update a column with an int based on order of another field
Reference: http://stackoverflow.com/a/10485817/345721
SET @rownumber = 0;
update mytable set Moneyorder = (@rownumber:=@rownumber+1)
order by MoneyOrder asc
or to do it in a single query you can try
update mytable cross join (select @rownumber := 0) r set Moneyorder = (@rownumber := @rownumber + 1) order by MoneyOrder asc

Click the following link to find a good article on how to get first n results from each category: http://www.xaprb.com/blog/2006/12/07/how-to-select-the-firstleastmax-row-per-group-in-sql/
PHP - Mysql: Get last error
mysql_error
PHP - Mysql: determine which database is selected?
function mysql_current_db() {
    $r = mysql_query("SELECT DATABASE()") or die(mysql_error());
    return mysql_result($r,0);
}

Wednesday, September 2, 2015

How to replace Microsoft-encoded quotes in PHP

Scenario: I need to replace Microsoft Word version of single and double quotations marks (“ ” ‘ ’) with regular quotes (' and ") due to an encoding issue in my application.

$search = array(
         chr(145),
         chr(146),
         chr(147),
         chr(148),
         chr(151)
);
$replace = array(
         "'",
         "'",
         '"',
         '"',
         '-'
 );
 return str_replace($search, $replace, $value);
Reference: http://stackoverflow.com/a/1262060/345721

Sunday, August 9, 2015

Android push

http://www.androidhive.info/2012/10/android-push-notifications-using-google-cloud-messaging-gcm-php-and-mysql/

https://github.com/mwillbanks/Zend_Mobile/tree/feature/gcm


Tips and tricks of GIT

Removing Files you have added files to Git that you want it to track no longer.

Scenario: You added a file to Git accidentally or you may want to remove a file from current push
You cannot run git rm because you want to keep a copy of the file(git rm command will delete the file from file system)


 Solution: To tell Git to stop tracking a file, but still keep it on your local system, run the following command

git rm --cached [file_name]
GIT - Ignore changes in a file
--Assume file to be unchanged
git update-index --assume-unchanged path/to/file.txt
GIT - Add all files that are tracked and has change

Scenario: I have modified large set of files and added new files as well and I want to stage only the tracked files. In such situations, I can use this command
git add -u

Using Branches

1. git branch
Usage: List all of the branches in your repository.

2. git branch <new_branch>
Usage: Create a new branch called <new_branch>. This does not check out the new branch.

3. git branch -d <branch>
Usage: Delete the specified branch. This is a “safe” operation since Git prevents you from deleting the branch if it has unmerged changes.

4. git branch -D <branch>
Usage: Force delete the specified branch. Use this command only if you want to permanantly discard all unmerged changes

5. git branch -m <new_branch>
Usage: Rename the current branch to <new_branch>.

6. git clone git@yourrepositry.com:projectidentifier new-folder-name
Usage: Clone git repository to a folder with different name.

7. git reset --hard
Usage: Resets your index and reverts the tracked files back to state as they are in HEAD.

8. git clean -f -d
Usage: Cleans untracked files.

9. git clean -f -d -x
Usage: Remove your .gitignored files and get back to a pristine state

10. git log branch_name..origin/branch_name
Usage: Find difference between my local branch and remote branch
GIT - Stash

11. git stash
Usage: Stash files for future reference

12. git stash show
Usage: List stashed files

13. git stash show -p
Usage: Show changes in stashed files

14. git stash save -p "message"
Usage: Lets you choose changes to be stashed, you can stash part of changes in a file as well

Tuesday, December 23, 2014

Handle images uploaded using multi file select using PHP in serverside


Multi file upload via ajax can be implemented using jQuery. You can find the detailed documentation here.
OR copy & paste the following link to address bar of your browser

<?php
/**
 * Function to save images uploaded from content tab using bulk upload
 *
 * @return multitype:array
 */
public function save_uploaded_files()
{
    $response = array('status' => 0, 'message' => '');
    $posted_data = $_POST;
    $user_name = $posted_data['username'];
    $config['allowed_types'] = array('gif','jpg', 'jpeg', 'jpe', 'png');
    $config['upload_path'] = getcwd().'/uploadpath/';

    $values = array();
    $originalFileName = '';
    try {
        $fileDetails = $this->process_uploaded_file($originalFileName, $values, $user_id);
    } catch (Exception $e) {
        $response['message'] = 'Something went wrong. Please try again later';

        return $response;
    }
    $response['status'] = 1;
    $response['message'] = 'Files saved';
    foreach ($fileDetails as $details) {
        $response['file_info'][] = array(
            'original' => $details['uploaded_file_name'],
            'target' => $details['target_name'],
        );
    }

    return $response;
}

/**
 * Function to move uploaded file to target location
 *
 * @param string $fileName
 * @param array $values pass by reference
 *
 * @return string file name
 */
public function process_uploaded_file()

    $bulk_upload = $_POST['bulk_upload'];
    $config['upload_path'] = getcwd().'/uploaded/';
    $config['allowed_types'] = array('gif','jpg', 'jpeg', 'jpe', 'png');
    $uploaded_file_info = false;
    $number_of_images = get_number_of_images_uploaded($_FILES['image_uploader_multiple']);
    if ($number_of_images > 0) {
        foreach ($_FILES['image_uploader_multiple']['name'] as $key => $uploaded_file_name) {
            $uploaded_path_parts = pathinfo($uploaded_file_name);
            $temp_name = $_FILES['image_uploader_multiple']['tmp_name'][$key];
            $fileName = uniqid('', true).".".date("YmdHis").".".sprintf("%06d",rand());
            $fileFullName = $fileName.".".$uploaded_path_parts['extension'];
            $target_path_parts = pathinfo($fileName);
            $target_file_name = $target_path_parts['filename'].'.'.$uploaded_path_parts['extension'];

            $i = 1;
            while (file_exists($config['upload_path'].$target_file_name)) {
                $target_file_name = $target_path_parts['filename'].'-'.($i++).'.'.$uploaded_path_parts['extension'];
            }
          
            $config['file_name'] = $target_file_name;
            move_uploaded_file($temp_name, $config['upload_path'].$target_file_name);
            chmod_apply($config['upload_path'].$target_file_name);

            $uploaded_file_info[] = array(
                'target_name' => $target_file_name,
                'uploaded_file_name' => $uploaded_file_name
            );
         }
    }

    return $uploaded_file_info;
}

/**
 * Function to get number of images uploaded
 *
 * @param array $image_uploader_multiple
 *
 * @return number
 */
function get_number_of_images_uploaded($image_uploader_multiple)
{
    $count = 0;
    if (isset($image_uploader_multiple['error']) && is_array($image_uploader_multiple['error'])) {
        foreach($image_uploader_multiple['error'] as $error) {
            if ($error != 4) {
                $count++;
            }
        }
    }

    return $count;
}

/**
 * Function to apply proper permission to the upload file
 *
 * @param $filename
 * @return bool
 */
function chmod_apply($filename = '') {
    $stat = @ stat(dirname($filename));
    $perms = $stat['mode'] & 0007777;
    $perms = $perms & 0000666;
    if ( @chmod($filename, $perms) )
        return true;
    return false;
}

Multi file select preview without uploading and delayed upload

  • Ajax file upload
  • Multi file select
  • Selective upload of files in multi select


Requirement: Implement a file selector with multiple file select with following functions.
1. Allow user to select images only.
1. Preview of all selected images should be populated on the page without uploading the image to the server on selecting images.
2. User should be able to  filter images to be actually uploaded to the server from the previews, User should be able to remove selected files using a close button.
3. On clicking upload button, the images listed in the preview should be uploaded to server without page re-load(Ajax).

Implementation plan:
1. User can select images using multiple File Input.
2. Preview of images selected can be  populated by using a FileReader object and can be appended to html preview area.
3. Index of selected images can be used to generate class name of the respective image container, sothat we can match images selected and the one which is previewed.
4. Using a button populated near preview, we can close the preview(Remove the element from the html dom - make sure the container with matching class name is also removed)
5. On clicking the upload button, we can iterate through the images selected in the file selector and search for the corresponding image preview container having matching class name to find if the preview of the image is not removed by the user, if present, add them to formData object and submit them via ajax to the server.

Screen shots:






Code on github: https://github.com/imaimai86/multi-file-select-preview-without-uploading-and-delayed-upload

Demo on jsFiddle: http://jsfiddle.net/anas/6v8Kz/7/embedded/result/

http://jsfiddle.net/anas/6v8Kz/7/ 

Code Hint:

HTML:
<p>
<label for="image_uploader_multiple">Image:</label>
</p>
<form>
<table width="70%" id="multi_file_uploader">
    <tbody>
        <tr class="imageSelectorContainer">
            <td valign="top">
                <input type="file" name="image_uploader_multiple[]" 

                value="" class="multipleImageFileInput" 
                style="width:50%" 
                onchange="show_image_preview(this);"  
                accept="image/*" multiple="">
                <!-- Preview container table -->
                <table class="imagePreviewTable"></table>
            </td>
            <td valign="top" align="right">
                <input type="button" value="X" title="Remove" 

                class="removeButton"  style="display:none;" 
                onclick="remove_file_uploader(this)">
            </td>
            <td valign="top">

                <input type="button" value="+"  title="Add" 
                class="addButton"  style="" 
                onclick="add_new_file_uploader(this)"> 
            </td>
        </tr>
    </tbody>
    <tbody>
        <tr>
            <td colspan="3" class="buttonBox">
                <input type="submit" value="Save Images">
            </td>
        </tr>
    </tbody>
</table>
</form>
<div class="overlay">
    <div class="overlay_content">Saving....<br />

        <img src="spinner.gif" />
    </div>
</div>

CSS:
<style type="text/css">
.buttonBox{
    padding: 20px;
    text-align: center;
}
.imagePreviewTable{
    border: 1px solid #000;
    display: none;
}
.overlay {
    position:absolute; top:0; left:0; right:0; bottom:0; background-color:rgba(0, 0, 0, 0.85); background: url(data:;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAYAAABytg0kAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAABl0RVh0U29mdHdhcmUAUGFpbnQuTkVUIHYzLjUuNUmK/OAAAAATSURBVBhXY2RgYNgHxGAAYuwDAA78AjwwRoQYAAAAAElFTkSuQmCC) repeat scroll transparent\9; /* ie fallback png background image */ z-index:9999; color:white; text-align:center; height:5000px; display:none;
}
.overlay_content{
    padding:300px;
}
</style>
 

JAVASCRIPT:
Include jquery 
<script type='text/javascript' src="https://ajax.googleapis.com/ajax/libs/jquery/1.5.1/jquery.min.js"></script>

Open "Script" tag
<script type="text/javascript">

Bind form submission with function to upload images using jQuery
$(document).ready(function(){
    $('form').submit(function(ev){
        $('.overlay').show();
        $(window).scrollTop(0);
        return upload_images_selected(ev, ev.target);
    })
})

Function to display preview of images selected using the input selector. 
Logic: For each images selected, add a preview row to the image preview table, with a class name corresponding to the index of the file in the file selector(imagePreviewRow_<index_of_image_in_file_selector>). Iterate through the files selected using the file selector input and check the mime type of the selected file, if it is an image, create a file reader object to read the content of the file and append file content to the preview row.
function show_image_preview(file_selector) {
    //files selected using current file selector
    var files = file_selector.files;
    //Container of image previews
    var imageContainer = $(file_selector).next('table.imagePreviewTable');
    //Number of images selected
    var number_of_images = files.length;
    //Build image preview row
    var imagePreviewRow = $( '<tr class="imagePreviewRow_0">'+

                                                 '<td valign=top style="width: 510px;"></td>' +                                                  '<td valign=top><input type="button" '+ 
                                                  ''value="X"  title="Remove Image"'+ 
                                                  ' class="removeImageButton" '+
                                                  'imageIndex="0" '+
                                                  ' onclick="remove_selected_image(this)" />'+
                                                  '</td></tr> ');
    //Add image preview row
    $(imageContainer).html(imagePreviewRow);
    if (number_of_images > 1) {
        for (var i =1; i<number_of_images; i++) {
            /**
             * Generate class name of the respective image container appending index 

             * of selected images, sothat we can match images selected and 
             * the one which is previewed
             */

            var newImagePreviewRow = $(imagePreviewRow)

                                                               .clone()
                                                               .removeClass('imagePreviewRow_0')
                                                               .addClass('imagePreviewRow_'+i);
            $(newImagePreviewRow).find('input[type="button"]').attr('imageIndex', i);
            $(imageContainer).append(newImagePreviewRow);
        }
    }
    for (var i = 0; i < files.length; i++) {
        var file = files[i];
        /**
         * Allow only images
         */

        var imageType = /image.*/;
        if (!file.type.match(imageType)) {
          continue;
        }
       
        /**
         * Create an image dom object dynamically
         */

        var img = document.createElement("img");
       
        /**
         * Get preview area of the image
         */

        var preview = $(imageContainer).find('tr.imagePreviewRow_'+i).find('td:first');

        /**
         * Append preview of selected image to the corresponding container
         */

        preview.append(img);
       
        /**
         * Set style of appended preview(Can be done via css also)
         */

        preview.find('img').addClass('previewImage')

                                     .css({'max-width': '500px', 'max-height': '500px'});
       
        /**
         * Initialize file reader
         */

        var reader = new FileReader();
        /**
         * Onload event of file reader assign target image to the preview
         */

        reader.onload = (function(aImg) { return function(e) { 

            aImg.src = e.target.result; }; 
        })(img);
        /**
         * Initiate read
         */

        reader.readAsDataURL(file);
    }
    /**
     * Show preview
     */

    $(imageContainer).show();
}

Function to remove selected image from preview. This function removes the image from DOM instead of hiding them.
function remove_selected_image(close_button)
{
    /**
     * Remove this image from preview
     */

    var imageIndex = $(close_button).attr('imageindex');
    $(close_button).parents('.imagePreviewRow_' + imageIndex).remove();
}

Function to upload remaining images available in the preview list.
Logic: Iterate through each file input and each files selected, and check if the image is in the preview. this checking can be done easily by checking the image preview row with name(imagePreviewRow_<index_of_image_in_file_selector>) corresponding to the index of the file in the file selector input exists. If the preview is available, create a formData object and append the image to the object. Now post the form data object using "XMLHttpRequest" to the server(Ajax).
This function sends an ajax request corresponding to each file selector to tackle the maximum file upload size limit that can be uploaded to the server. This method avoids uploading large number of files simultaneously to the server there by getting caught by the max file upload limit.
function upload_images_selected(event, formObj)
{
    event.preventDefault();
    //Get number of images
    var imageCount = $('.previewImage').length;
    //Get all multi select inputs
    var fileInputs = document.querySelectorAll('.multipleImageFileInput');
    //Url where the image is to be uploaded
    var url= "/admin/content/upload";
    //Get number of inputs
    var number_of_inputs = $(fileInputs).length;
    var inputCount = 0;

    //Iterate through each file selector input
    $(fileInputs).each(function(index, input){
       
        fileList = input.files;
        // Create a new FormData object.
        var formData = new FormData();
        //Extra parameters can be added to the form data object
        formData.append('bulk_upload', '1');
        formData.append('username', $('input[name="username"]').val());
        //Iterate throug each images selected by each file selector and 

        //find if the image is present in the preview
        for (var i = 0; i < fileList.length; i++) {
            if($(input).next('.imagePreviewTable').find('.imagePreviewRow_'+i).length!=0){
                var file = fileList[i];
                // Check the file type.
                if (!file.type.match('image.*')) {
                    continue;
                }
                // Add the file to the request.
                formData.append('image_uploader_multiple[' +(inputCount++)+ ']', 

                                              file, 
                                              file.name);
            }
        }
        // Set up the request.
        var xhr = new XMLHttpRequest();
        xhr.open('POST', url, true);
        xhr.onload = function () {
            if (xhr.status === 200) {
                var jsonResponse = JSON.parse(xhr.responseText);
                if (jsonResponse.status == 1) {
                    $(jsonResponse.file_info).each(function(){
                        //Iterate through response and find data corresponding 

                        //to each file uploaded
                        var uploaded_file_name = this.original;
                        var saved_file_name = this.target;
                        var file_name_input = '<input type="hidden" class="image_name"

                                                             name="image_names[]" 
                                                             value="' +saved_file_name+ '" />';
                        file_info_container.append(file_name_input);
                       
                        imageCount--;
                    })
                    //Decrement count of inputs to find all images 

                    //selected by all multi select are uploaded
                    number_of_inputs--;
                    if(number_of_inputs == 0) {
                        //All images selected by each file selector is uploaded
                        //Do necessary acteion post upload
                        $('.overlay').hide();
                    }
                } else {
                    if (typeof jsonResponse.error_field_name != 'undefined') {
                        //Do appropriate error action
                    } else {
                        alert(jsonResponse.message);
                    }
                    $('.overlay').hide();
                    event.preventDefault();
                    return false;
                }
            } else {
                alert('Something went wrong!');
                $('.overlay').hide();
                event.preventDefault();
            }
        };
        xhr.send(formData);
    })
   
    return false;
}


Function to populate new file uploader on clicking the "+" button near to existing file selectors. On clicking the "+" button, the row containing the "+" button is cloned, selected files and previews if any are removed and appended to the end of the container.
function add_new_file_uploader(addBtn) {
    var currentRow = $(addBtn).parent().parent();
    var newRow = $(currentRow).clone();
    $(newRow).find('.previewImage, .imagePreviewTable').hide();
    $(newRow).find('.removeButton').show();
    $(newRow).find('table.imagePreviewTable').find('tr').remove();
    $(newRow).find('input.multipleImageFileInput').val('');
    $(addBtn).parent().parent().parent().append(newRow);
}

File selector along with selected images are removed.
function remove_file_uploader(removeBtn) {
    $(removeBtn).parent().parent().remove();
}

Close "Script" tag
</script>

Serverside PHP code to handle uploads can be found here
OR copy & paste the following link to address bar of your browser

Customize file select input here
OR copy & paste the following link to address bar of your browser