Tag Archives: PHP

Codeigniter Session Storage Alternative Method

The limit of a cookie is 4kb. If you choose to store codeigniter session data in the cookie then you should not exceed 4kb.

To store more than 4kb of session, you can set in config.php file with the following setting:

$config['sess_use_database']	= TRUE;

This allows you to store session data in database.

Refer to http://ellislab.com/codeigniter/user-guide/libraries/sessions.html on how to setup saving session data to database.

Alternative Method

An alternative method to store large session data without using database is to use CodeIgniter file-cache. This allows you to store session data into a file located in CodeIgniter cache folder.

Example:

function login(){
    $this->load->driver('cache');

    /* Do your user login validation here */
    $user_id = $this->myusermodel->verifyLogin();
    $this->session->set_userdata('users_id', $user_id);
    /* End of login validation */

    $session_data = $this->mymodel->get_my_big_data(); 
    $cache_user = array();
    $cache_user["session_data"] = $session_data;
    $this->cache->file->save('cu-' . $user_id, $cache_user, 100000000);
}

From example above, i store only the $user_id into the session and the rest into a cache file in the server. The cookie / session is now very small as it contains $user_id only.

Then, I save session data into a cache file. To ensure I am able to access the correct cache file when I want to retrieve the session data, I use ‘cu-‘ + $user_id  as the key. Note that the time-to-expire is set to unlimited as the data need to be used all the time.

About CodeIgniter Cache Library: http://ellislab.com/codeigniter/user-guide/libraries/caching.html#file

To retrieve session data:

function loadCache(){
    $this->load->driver('cache');
    $cache_id = 'cu-' . $this->session->userdata('users_id');
    $cache_user = $this->cache->file->get($cache_id);
    $session_data = $cache_user["session_data"];

    //Perform operation on $session_data here.
}

To retrieve session data, simply call $this->cache->file->get($cache_id). The returned object is exactly what has been saved.

Note: To ensure the safety of the cached data, ensure you put the cache folder outside of WWW or use .htaccess to disable access to any files in cache folder.

To change the location of the cache folder, modify the following in config.php file:

$config['cache_path'] = '/mydrive/safefolder/cache'; //Ensure this folder is writable by apache

Good luck on the implementation and have fun.

PHP HTML Entities String Function For Javascript Function Not Working Solution – Simple Concept

“Uncaught SyntaxError: Unexpected token ILLEGAL” is a common error when input parameter of JavaScript function is not closed properly.

1) To escape JavaScript parameter, we use PHP htmlentities function. However, even with PHP htmlentities, we might still encounter this issue. Consider the following example:

 PHP Code:

echo "<a href='javascript:showContent(\"" . htmlentities ("Edit Service Sushi's Shop", ENT_QUOTES) . "\");'></a>";

2) Now the string should be Edit Service Sushi&apos;s Shop.

3) However, when this string reaches browser, the string gets unescaped and becomes:

<a href='javascript:showContent("Edit Service Sushi's Shop");'></a>

4) Hence, the JavaScript function breaks when user click on this link.

5) To solve this, we need to double-escape the string.

echo "<a href='javascript:showContent(\"" . htmlentities(htmlentities("Edit Service Sushi's Shop", ENT_QUOTES), ENT_QUOTES) . "\");'></a>";

6) Now the string becomes Edit Service Sushi&amp;apos;s Shop. The string parameter is now safe. We can use this parameter string as input for jQuery.html() function without breaking the JavaScript function.

<a href='javascript:showContent("Edit Service Sushi&apos;s Shop");'></a>

<script>
function showContent(input){
   $("#mydiv").html(input); 
   //the escaped characters will be unescaped via .html function
}
</script>

jQuery Images Crossfading Front Page Banner – Simple Stuffs

Creating a crossfading images slideshow for a homepage is easy. All you need is jQuery.

Steps as follow:

1) Assuming we have 3 images. All these images have same height and width, and positioned absolute. Each of these images are overlapping on top of each other.

<div>
	<img id="home-image-1" class="position-absolute" src="home-image-1.png"/>
	<img id="home-image-2" class="position-absolute" src="home-image-2.png"/>
	<img id="home-image-3" class="position-absolute" src="home-image-3.png"/>
</div>
.position-absolute{
	position: absolute;
}

2) Hide second and third image using jQuery hide(). Now we have only one image showing.

3) Next, we need to make the second image fading in after a certain amount of time in crossfading manner. To do this, we will set first and third images to have z-index = 0 while second image to have z-index = 1.

Note we have second image on top of all other images and it is still hidden. Call fadeIn(‘slow’) for second image.

4) Once fadeIn() animation for second image is completed, call hide() for first and third images.

5) Repeat this method for next images.

To see how to create continues looping of crossfading images, see code sample below:

<script>
	$(document).ready(function(){
		$("#home-image-2, #home-image-3").hide(); //Show first image and hide the rest.
		setInterval(function(){loopHomeImages();},5000);
	});

	var curr = 1;

	function loopHomeImages(){
		var after = (this.curr + 1)%3; //Next image in the loop
		var bef = ((curr - 1) >= 0) ? (curr - 1) : 2; //Previous image in the loop

		$(".position-absolute").css("z-index", 0);
		$("#home-image-" + curr).css("z-index", 1);
		$("#home-image-" + curr).fadeIn("slow", function(){
			$("#home-image-" + after).hide();
			$("#home-image-" + bef).hide();
		});
		curr = (curr + 1)%3;
	}
</script>

That’s all.

Good luck and have fun.

CodeIgniter Resize and Crop Image To Fit Container Div Example

When a user uploads an image to be displayed on a webpage, we need to make sure that the image has the following:

a) fits correctly into a fixed height and width container without overflowing or any blank space.
b) displays in full image resolution (without shrinking or expanding image using CSS width and height).
c) image displayed is not skewed or distorted and keeping image ratio.

References to CodeIgniter libraries:
http://ellislab.com/codeigniter/user-guide/libraries/file_uploading.html
http://ellislab.com/codeigniter/user-guide/libraries/image_lib.html

By using CodeIgniter framework, I manage to achieve the above.

Workflow:

1) Upload the raw image using standard file upload form. Upload handling backend:

$config['upload_path'] = './data/product/';
$config['allowed_types'] = 'gif|jpg|png';
$config['file_name'] = 'product.png';
$config['overwrite'] = TRUE;
$config['max_size']	= '0';
$config['max_width']  = '0';
$config['max_height']  = '0';	

$this->load->library('upload', $config);

if(!is_dir($config['upload_path'])){
   	mkdir($config['upload_path'], 0755, TRUE);
}

if (!$this->upload->do_upload("file_upload")){ //Upload file
			redirect("errorhandler"); //If error, redirect to an error page
		}else{
  ...

2) Next, we will do image resizing. Set the configuration as below:

   
$upload_data = $this->upload->data();
$image_config["image_library"] = "gd2";
$image_config["source_image"] = $upload_data["full_path"];
$image_config['create_thumb'] = FALSE;
$image_config['maintain_ratio'] = TRUE;
$image_config['new_image'] = $upload_data["file_path"] . 'product.png';
$image_config['quality'] = "100%";
$image_config['width'] = 231;
$image_config['height'] = 154;
$dim = (intval($upload_data["image_width"]) / intval($upload_data["image_height"])) - ($image_config['width'] / $image_config['height']);
$image_config['master_dim'] = ($dim > 0)? "height" : "width";

$this->load->library('image_lib');
$this->image_lib->initialize($image_config);

if(!$this->image_lib->resize()){ //Resize image
	redirect("errorhandler"); //If error, redirect to an error page
}else{
     ...

Explanation: “maintain_ratio” parameter is set to TRUE. From code above, the container size used for this example is (231px × 154px) (W × H).

Before resizing, we need to know whether to use width or height edge as the hard-value. After the original image has been resized, either the original image width’s edge or the height’s edge will be the same as the container width’s edge or the height’s edge respectively. The one that is same has the hard-value length. We determine this using calculation below:

Ratio = (Original Image Width / Original Image Height) – (Container Width / Container Height)

If the ratio > 0, then original image has longer width than container width. Hence, we take the height as hard-value as it has shorter height ratio.
If the ratio < 0, then original image has longer height than container height. Hence, we take width as hard-value as it has shorter width ratio.
if ratio = 0, both width or height can be the hard-value.

The purpose of doing this is to ensure resized image is able to fill the container completely without white spaces.

See visual description below:

Compare

Above shows container and image with different sizes.

Overlap

To determine which edge to be used as hard-value, we overlap the container and the original image. We will shrink the original image while keeping its ratio. The arrow indicates the shrinking direction. The edge of the image that first matches the container edge length will be the hard-value.

Image_07

When either one of the edge matches the container edge, we stop resizing. The orange box represents the final image.

3) After resizing the image, we will crop it to fit into the container. Set the configurations as below:

$image_config['image_library'] = 'gd2';
$image_config['source_image'] = $upload_data["file_path"] . 'product.png';
$image_config['new_image'] = $upload_data["file_path"] . 'product.png';
$image_config['quality'] = "100%";
$image_config['maintain_ratio'] = FALSE;
$image_config['width'] = 231;
$image_config['height'] = 154;
$image_config['x_axis'] = '0';
$image_config['y_axis'] = '0';

$this->image_lib->clear();
$this->image_lib->initialize($image_config); 

if (!$this->image_lib->crop()){
       	redirect("errorhandler"); //If error, redirect to an error page
}else{
	redirect("successpage");
}

Note that ‘x_axis‘ and ‘y_axis‘ are set to 0. We don’t need to crop away any parts. We will use width and height parameters to generate the image part that we need.

Final

Image resizing and cropping to fit into container is done.

Saving Image To Database Using PHP

Images are usually located in assets/images folder of your application. Web users can easily access your images using direct URL without logging in. If you are storing users’ uploaded images in your web server folder, someone might be able to steal your important images. For example, photo of employees.

Another issue is if you have multiple application servers running the same application to serve many HTTP request concurrently, images uploaded by users may be stored in either one of the server. Hence, when another user trying to view image uploaded, the image may appear missing. See image below.

Image Missing When Using Multiple Application Server

Image Missing When Using Multiple Application Server

There are many ways to solve this issue. Here is how I solve it. Saving the image into the database.

Summary of workflow:
Saving Image
1) Uploaded image will be saved in one of the server folder.
2) Convert the image binary string to base64 string using PHP base64_encode.
3) Store base64 string in database as longtext type.

Loading Image
4) Load base64 string containing image from database.
5) Convert base64 string to binary using PHP base64_decode.
6) Set return type header as ‘image/png‘.
7) Echo the binary data.

See sample code below.

File Upload Form:

<html>
<body>

<form action="backend.php" method="POST" enctype="multipart/form-data">
	<input type="file" name="file"/>
	<br />
	<input type="submit"/>
</form>

</body>
</html>

Backend:

<?php
if(!isset($_GET["getfile"])){
	if ($_FILES["file"]["error"] > 0){
		echo "Error: " . $_FILES["file"]["error"] . "<br>";
	}else{
		move_uploaded_file($_FILES["file"]["tmp_name"], $_FILES["file"]["name"]);
		$bin_string = file_get_contents($_FILES["file"]["name"]);
		$hex_string = base64_encode($bin_string);
		$mysqli = mysqli_init();
		if (!$mysqli->real_connect('localhost', 'root', '', 'test')) {
			die('Connect Error (' . mysqli_connect_errno() . ') ' . mysqli_connect_error());
		}
		$mysqli->query("INSERT INTO upload(image) VALUES ('" . $hex_string . "')");
	}
}else{
	$mysqli = mysqli_init();
	if ($mysqli->real_connect('localhost', 'root', '', 'test')) {
		if ($result = $mysqli->query("SELECT * FROM upload ORDER BY id DESC")){
			if($row = $result->fetch_assoc()){
				$output_hex_string = $row["image"];
				$output_bin_string = base64_decode($output_hex_string);
				header("Content-Type: image/png");
				header("Content-Length: " . strlen($output_bin_string));
				$result->free();	
				echo $output_bin_string;
			}
		}
	}
  }
?>  

<img src="backend.php?getfile=1" />

Note: The last line of code ‘<img src=”backend.php?getfile=1″ />’. Note the “src”  parameter. By using this method, we can just call a PHP function within the src tag and the browser will take the PHP output as image to display. This inline method is clean and easy to use. In addition, we can preprocess the image output or perform access control before displaying.

MySQL allows storage of binary data but I am storing it as hex string. The reason is I won’t need to handle not 8-bit clean characters or null characters that might break the code during saving process.