Changes to the viewSince all of the media types we are going to support require at least one additional database field in a table that extends the statuses table, we are going to need to
Trang 1Changes to the view
Since all of the media types we are going to support require at least one additional
database field in a table that extends the statuses table, we are going to need to
display any additional fields on the post status form The standard type of status
doesn't require additional fields, and new media types that we haven't discussed,
which we may wish to support in the future, may require more than one additional
field To support a varying number of additional fields depending on the type, we
could use some JavaScript (in this case, we will use the jQuery framework) to change
the form depending on the context of the status Beneath the main status box, we can
add radio buttons for each of the status types, and depending on the one the user
selects, the JavaScript can show or hide the additional fields, making the form
more relevant
Template
Our update status template needs a few changes:
• We need to set the enctype on the form, so that we can upload files (for
posting images)
• We need radio buttons for the new types of statuses
• We need additional fields for those statuses
The changes are highlighted in the following code segment:
<p>Tell your network what you are up to</p>
<form action="profile/statuses/{profile_user_id}" method="post"
enctype="multipart/form-data">
<textarea id="status" name="status"></textarea>
<br />
<input type="radio" name="status_type" id="status_checker_update"
class="status_checker" value="update" />Update
<input type="radio" name="status_type" id="status_checker_video"
class="status_checker" value="video" />Video
<input type="radio" name="status_type" id="status_checker_image"
class="status_checker" value="image" />Image
<input type="radio" name="status_type" id="status_checker_link"
class="status_checker" value="link" />Link
<br />
<div class="video_input extra_field">
<label for="video_url" class="">YouTube URL</label>
Trang 2<label for="image_file" class="">Upload image</label>
<input type="file" id="" name="image_file" class="" /><br />
</div>
<div class="link_input extra_field">
<label for="link_url" class="">Link</label>
<input type="text" id="" name="link_url" class="" /><br />
<label for="link_description" class="">Description</label>
<input type="text" id="" name="link_description" class="" /><br />
</div>
<input type="submit" id="updatestatus" name="updatestatus"
value="Update" />
</form>
These changes also need to be made to the post template, for posting on another
user's profile
jQuery to enhance the user experience
For accessibility purposes, we need this form to function regardless of whether the
user has JavaScript enabled on their browser To that end, we should use JavaScript
to hide the unused form elements So, even if the user has JavaScript disabled, they
can still use all aspects of the form We can then use JavaScript to enhance the user
experience, toggling which aspects of the form are hidden or shown
<script type="text/javascript">
$(function() {
First, we hide all of the extended status fields
$('.extra_field').hide();
$("input[name='status_type']").change(function(){
When the user changes the type of status, we hide all of the extended fields
$('.extra_field').hide();
We then show the fields directly related to the status type they have chosen
$('.'+ $("input[name='status_type']:checked").val() +
'_input').show();
});
});
</script>
Trang 3View in action
If we now take a look at our status updates page for our profile, we have some radio
buttons that we can use to toggle elements of the form
Images
To process images as a new status type, we will need a new database table and a new
model to extend from the main status model We will also need some new views,
and to change the profile and status stream controllers (though we will make those
changes after adding the three new status types)
Database table
The database table for images simply needs two fields:
ID Integer, Primary key To relate to the main statuses table
Trang 4The model needs to extend our statuses model, providing setters for any new fields,
call the parent constructor, call the parent setTypeReference method to inform that
it is an image, call the parent save method to save the status, and then insert a new
record into the image status table with the image information
Class, variable, and constructor
Firstly, we define the class as an extension of the status class We then define a
variable for the image, and construct the object The constructor calls the parent
setTypeReference method to ensure it generates the correct type ID for an image,
and then calls the parent constructor so it too has reference to the registry object
This file is saved as /models/imagestatus.php
<?php
/**
* Image status object
* extends the base status object
*/
class Imagestatus extends status {
private $image;
/**
* Constructor
* @param Registry $registry
* @param int $id
* @return void
*/
public function construct( Registry $registry, $id = 0 )
{
$this->registry = $registry;
parent::setTypeReference('image');
parent:: construct( $this->registry, $id );
}
To call a method from an object's parent class, we use the parent keyword, followed by the scope resolution operator, followed by the method we wish to call
Trang 5Processing the image upload
When dealing with image uploads, resizing, and saving, there are different PHP
functions that should be used depending on the type of the image To make this
easier and to provide a centralized place for dealing with image uploads and other
image-related tasks, we should create a library file (lib/images/imagemanager
class.php) to make this easier
Let's discuss what an image manager library file should do to make our lives easier:
• Process uploading of an image from $_POST data
° Verify the type of file and the file extension
• Process images from the file system so that we can modify them
• Display an image to the browser
• Resize an image
• Rescale an image by resizing either the x or y co-ordinate, and scaling
the other co-ordinate proportionally
• Get image information such as size and name
• Save the changes to the image
The following is the code required to perform the above-mentioned tasks:
<?php
/**
* Image manager class
* @author Michael Peacock
*/
class Imagemanager
{
/**
* Type of the image
*/
private $type = '';
/**
* Extensions that the user can upload
*/
private $uploadExtentions = array( 'png', 'jpg', 'jpeg', 'gif' );
/**
* Mime types of files the user can upload
Trang 6/**
* The image itself
*/
private $image;
/**
* The image name
*/
private $name;
public function construct(){}
We need a method to load a local image, so that we can work with images saved
on the servers file system
/**
* Load image from local file system
* @param String $filepath
* @return void
*/
public function loadFromFile( $filepath )
{
Based on the path to the image, we can get information on the image including
the type of image (getimagesize gives us an array of information on the image;
the second element in the array is the type)
$info = getimagesize( $filepath );
$this->type = $info[2];
We can then compare the image type to various PHP constants, and depending
on the image type (JPEG, GIF, or PNG) we use the appropriate imagecreatefrom
function
if( $this->type == IMAGETYPE_JPEG )
{
$this->image = imagecreatefromjpeg($filepath);
}
elseif( $this->type == IMAGETYPE_GIF )
{
$this->image = imagecreatefromgif($filepath);
}
elseif( $this->type == IMAGETYPE_PNG )
{
$this->image = imagecreatefrompng($filepath);
}
}
Trang 7We require a couple of getter methods to return the height or width of the image.
/**
* Get the image width
* @return int
*/
public function getWidth()
{
return imagesx($this->image);
}
/**
* Get the height of the image
* @return int
*/
public function getHeight()
{
return imagesy($this->image);
}
We use a simple resize method that resizes the image to the dimensions we request
/**
* Resize the image
* @param int $x width
* @param int $y height
* @return void
*/
public function resize( $x, $y )
{
$new = imagecreatetruecolor($x, $y);
imagecopyresampled($new, $this->image, 0, 0, 0, 0, $x, $y,
$this->getWidth(), $this->getHeight());
$this->image = $new;
}
Here we use a scaling function that takes a height parameter to resize to and scales
the width accordingly
/**
* Resize the image, scaling the width, based on a new height
* @param int $height
Trang 8$width = $this->getWidth() * ( $height / $this->getHeight() );
$this->resize( $width, $height );
}
Similar to the above method, this method takes a width parameter, resizes the width,
and rescales the height based on the width
/**
* Resize the image, scaling the height, based on a new width
* @param int $width
* @return void
*/
public function resizeScaleHeight( $width )
{
$height = $this->getHeight() * ( $width / $this->getWidth() );
$this->resize( $width, $height );
}
The following is another scaling function, this time to rescale the image to a
percentage of its current size:
/**
* Scale an image
* @param int $percentage
* @return void
*/
public function scale( $percentage )
{
$width = $this->getWidth() * $percentage / 100;
$height = $this->getheight() * $percentage / 100;
$this->resize( $width, $height );
}
To output the image to the browser from PHP, we need to check the type of the
image, set the appropriate header based off the type, and then use the appropriate
image function to render the image After calling this method, we need to call
exit() to ensure the image is displayed correctly
/**
* Display the image to the browser - called before output is sent,
exit() should be called straight after.
* @return void
*/
public function display()
{
if( $this->type == IMAGETYPE_JPEG )
Trang 9{
$type = 'image/jpeg';
}
elseif( $this->type == IMAGETYPE_GIF )
{
$type = 'image/gif';
}
elseif( $this->type == IMAGETYPE_PNG )
{
$type = 'image/png';
}
header('Content-Type: ' $type );
if( $this->type == IMAGETYPE_JPEG )
{
imagejpeg( $this->image );
}
elseif( $this->type == IMAGETYPE_GIF )
{
imagegif( $this->image );
}
elseif( $this->type == IMAGETYPE_PNG )
{
imagepng( $this->image );
}
}
To load an image from $_POST data, we need to know the post field the image is
being sent through, the directory we wish to place the image in, and any additional
prefix we may wish to add to the image's name (to prevent conflicts with images
with the same name)
/**
* Load image from postdata
* @param String $postfield the field the image was uploaded via
* @param String $moveto the location for the upload
* @param String $name_prefix a prefix for the filename
* @return boolean
*/
public function loadFromPost( $postfield, $moveto,
Trang 10Before doing anything, we should check that the file requested is actually a file that
has been uploaded (and that this isn't a malicious user trying to access other files)
if( is_uploaded_file( $_FILES[ $postfield ]['tmp_name'] ) )
{
$i = strrpos( $_FILES[ $postfield ]['name'], '.');
if (! $i )
{
//'no extention';
return false;
}
else
{
We then check that the extension of the file is in our allowed extensions array
$l = strlen( $_FILES[ $postfield ]['name'] ) - $i;
$ext = strtolower ( substr( $_FILES[ $postfield ]['name'],
$i+1, $l ) );
if( in_array( $ext, $this->uploadExtentions ) )
{
Next, we check if the file type is an allowed file type
if( in_array( $_FILES[ $postfield ]['type'],
$this->uploadTypes ) )
{
Then, we move the file, as it has already been uploaded to our server's temp folder,
to our own uploads directory and load it into our image manager class for any
further processing we wish to make
$name = str_replace( ' ', '', $_FILES[
$postfield ]['name'] );
$this->name = $name_prefix $name;
$path = $moveto $name_prefix.$name;
move_uploaded_file( $_FILES[ $postfield ]['tmp_name'] ,
$path );
$this->loadFromFile( $path );
return true;
}
else
{
// 'invalid type';
return false;
}
}