Prevent Anytthing but Img Being Uploaded Php

17 May 2019: This article and the code were updated for PHP7 compatibility.

In my tutorial Build a CMS in an Afternoon with PHP and MySQL, I showed how to build a unproblematic but useful content management system with PHP and MySQL. I too showed how to extend the CMS to let article categories.

In this tutorial, y'all'll look at another way to extend the CMS. You'll take the original CMS lawmaking, and change it then that the administrator can upload an image for each article. Then, when a company views an commodity page, the CMS will display the image at the outset of the article. In addition, our CMS will generate a smaller thumbnail version of each article prototype, and display this thumbnail adjacent to each article headline in the homepage and commodity archive pages.

You can meet the finished issue by clicking the View Demo link above. Observe the thumbnail images next to each article headline. Click a headline or thumbnail to view the respective article, forth with the total-size commodity paradigm.

The plan

We'll start with the original CMS code from Build a CMS in an Afternoon with PHP and MySQL, and alter it to include the prototype upload feature. Here are the steps we'll demand to conduct out:

  1. Create a couple of folders to store the commodity images
  2. Modify various image-related settings to the CMS config file
  3. Modify the database to shop the image filename extensions
  4. Modify the Commodity class to handle images
  5. Modify admin.php to handle image upload and deletion
  6. Modify the forepart-end templates to display the article images and thumbnails
  7. Modify the back-terminate commodity edit grade to let the administrator upload an epitome, view the commodity image, and delete the article image
  8. Tweak the CMS stylesheet to manner the article images and the new elements in the article edit form

Ready? Let's get started!

Stride 1: Create the image folders

The showtime thing to practise is create a couple of folders in your website to store the full-size and thumbnail article images.

Open up the existing cms folder and yous'll run across an images folder containing the sample logo.jpg image. Inside this images folder, create an articles folder. And so, inside the articles folder, create two more folders:

  • fullsize to store the total-size article images
  • thumb to store the smaller thumbnail versions of the article images

Next you demand to requite your web server user permission to create files in these 2 folders. Typically on a Linux or Mac arrangement, you need to change the permissions to 777, like this:

$ cd images/articles/ $ chmod 777 fullsize $ chmod 777 pollex        

If your CMS is on a remote web server then you lot can usually set up these permissions using your FTP software.

Step 2: Edit the config file

The next step is to add some image-related constants to the CMS config file. Open up upwards the config.php file in the meridian-level cms binder, and add the new lines highlighted in the code below:

<?php ini_set( "display_errors", truthful ); date_default_timezone_set( "Australia/Sydney" );  // http://www.php.net/transmission/en/timezones.php define( "DB_DSN", "mysql:host=localhost;dbname=cms" ); define( "DB_USERNAME", "username" ); define( "DB_PASSWORD", "password" ); define( "CLASS_PATH", "classes" ); define( "TEMPLATE_PATH", "templates" ); define( "HOMEPAGE_NUM_ARTICLES", v ); define( "ADMIN_USERNAME", "admin" ); define( "ADMIN_PASSWORD", "mypass" ); define( "ARTICLE_IMAGE_PATH", "images/articles" ); define( "IMG_TYPE_FULLSIZE", "fullsize" ); define( "IMG_TYPE_THUMB", "pollex" ); ascertain( "ARTICLE_THUMB_WIDTH", 120 ); define( "JPEG_QUALITY", 85 ); require( CLASS_PATH . "/Article.php" );  function handleException( $exception ) {   repeat "Sorry, a trouble occurred. Please effort later.";   error_log( $exception->getMessage() ); }  set_exception_handler( 'handleException' ); ?>        

You've added the following constants:

  • ARTICLE_IMAGE_PATH defines the path to the commodity images folder, relative to the top-level CMS folder. (If you desire to store your article images somewhere else, modify this constant accordingly.)
  • IMG_TYPE_FULLSIZE defines a abiding to correspond the "full-size" epitome type. We'll apply this in the lawmaking whenever we want to bespeak a full-size image. This value ("fullsize") is too used to locate the full-size images folder (images/articles/fullsize), and so if you use a different folder name, you'll want to update this abiding also.
  • IMG_TYPE_THUMB does a like task to IMG_TYPE_FULLSIZE, merely represents the "thumbnail" image blazon instead.
  • ARTICLE_THUMB_WIDTH defines the width to apply for the article thumbnail images, in pixels. Our prototype-handling lawmaking will use this value when generating the thumbnail versions of article images when they're uploaded.
  • JPEG_QUALITY defines the quality level to use when generating thumbnail versions of JPEG images. The value ranges from 0 to 100, where 100 is the all-time quality (but largest file size). 85 is a good compromise.

Pace 3: Alter the database

Safe

You need to make one small change to the articles table in the CMS database. Open up the tables.sql file from the original CMS, and add the line highlighted in the code below:

DROP TABLE IF EXISTS articles; CREATE TABLE articles (   id              smallint unsigned Not Zippo auto_increment,   publicationDate appointment NOT NULL,                              # When the article was published   championship           varchar(255) Non NULL,                      # Full title of the article   summary         text NOT NULL,                              # A short summary of the article   content         mediumtext Non NULL,                        # The HTML content of the commodity   imageExtension  varchar(255) Not NULL,                      # The filename extension of the commodity'southward total-size and thumbnail images    PRIMARY KEY     (id) );        

This line adds a new field chosen imageExtension to the articles table. This field stores the filename extension of each article's uploaded image. For example, if the administrator uploads a PNG image then we'll store the value ".png" in the imageExtension field.

What if you already take articles in your CMS?

If yous load the above tables.sql file into MySQL then information technology will delete any existing articles tabular array in your cms database, and recreate the articles table from scratch. This will delete whatsoever articles already in your CMS, which is obviously not what you desire.

So if y'all already have articles in your CMS database, you want to alter the articles table while retaining the existing information in the table. To do this, modify your tables.sql file to the post-obit:

Alter TABLE articles ADD imageExtension varchar(255) NOT Zero AFTER content;        

Applying the changes

To actually create your articles table (or add the new imageExtension field to your existing articles table, as appropriate), you need to load the tables.sql file into MySQL. To exercise this, follow the procedure described in Applying the changes in my last tutorial.

To check that your changes have been made, first login to MySQL:

mysql -u username -p cms

Then apply the Testify TABLES and Explicate commands to check your tabular array schemas in MySQL:

                      mysql> evidence tables; +---------------+ | Tables_in_cms | +---------------+ | manufactures      | +---------------+ ane row in set (0.00 sec)   mysql> explain articles; +-----------------+----------------------+------+-----+---------+----------------+ | Field           | Type                 | Nada | Primal | Default | Actress          | +-----------------+----------------------+------+-----+---------+----------------+ | id              | smallint(5) unsigned | NO   | PRI | Nix    | auto_increment | | publicationDate | appointment                 | NO   |     | Nada    |                | | title           | varchar(255)         | NO   |     | NULL    |                | | summary         | text                 | NO   |     | NULL    |                | | content         | mediumtext           | NO   |     | Zero    |                | | imageExtension  | varchar(255)         | NO   |     | Naught    |                | +-----------------+----------------------+------+-----+---------+----------------+ half-dozen rows in set (0.00 sec)  mysql>                  

Notice the new imageExtension field within the articles table.

You lot've prepare your CMS database so that it'due south prepare to handle image uploads. At present you can kickoff modifying the CMS code.

Pace 4: Modify the Commodity grade

Cogs

Next, we need to modify the Article course to handle article images. Here'southward the updated Article.php class file. I've highlighted the lines of code and then you lot tin meet what's been added and changed. Replace the code in your existing cms/classes/Article.php file with this new code:

<?php  /**  * Form to handle manufactures  */  class Article {   // Properties    /**   * @var int The article ID from the database   */   public $id = null;    /**   * @var int When the article is to exist / was starting time published   */   public $publicationDate = null;    /**   * @var string Full title of the article   */   public $title = null;    /**   * @var string A short summary of the article   */   public $summary = nil;    /**   * @var string The HTML content of the article   */   public $content = aught;    /**   * @var string The filename extension of the article's full-size and thumbnail images (empty string ways the article has no image)   */   public $imageExtension = "";     /**   * Sets the object's properties using the values in the supplied array   *   * @param assoc The property values   */    public function __construct( $information=array() ) {     if ( isset( $data['id'] ) ) $this->id = (int) $data['id'];     if ( isset( $data['publicationDate'] ) ) $this->publicationDate = (int) $data['publicationDate'];     if ( isset( $data['title'] ) ) $this->title = preg_replace ( "/[^\.\,\-\_\'\"\@\?\!\:\$ a-zA-Z0-9()]/", "", $information['title'] );     if ( isset( $data['summary'] ) ) $this->summary = preg_replace ( "/[^\.\,\-\_\'\"\@\?\!\:\$ a-zA-Z0-9()]/", "", $information['summary'] );     if ( isset( $data['content'] ) ) $this->content = $data['content'];     if ( isset( $data['imageExtension'] ) ) $this->imageExtension = preg_replace ( "/[^\.\,\-\_\'\"\@\?\!\$ a-zA-Z0-nine()]/", "", $data['imageExtension'] );   }     /**   * Sets the object's properties using the edit form mail service values in the supplied array   *   * @param assoc The form post values   */    public part storeFormValues( $params ) {      // Store all the parameters     $this->__construct( $params );      // Parse and store the publication date     if ( isset($params['publicationDate']) ) {       $publicationDate = explode ( '-', $params['publicationDate'] );        if ( count($publicationDate) == 3 ) {         list ( $y, $m, $d ) = $publicationDate;         $this->publicationDate = mktime ( 0, 0, 0, $grand, $d, $y );       }     }   }     /**   * Stores any prototype uploaded from the edit form   *   * @param assoc The 'image' element from the $_FILES array containing the file upload data   */    public function storeUploadedImage( $image ) {      if ( $paradigm['error'] == UPLOAD_ERR_OK )     {       // Does the Article object have an ID?       if ( is_null( $this->id ) ) trigger_error( "Article::storeUploadedImage(): Attempt to upload an paradigm for an Article object that does not have its ID property set.", E_USER_ERROR );        // Delete whatever previous image(s) for this article       $this->deleteImages();        // Get and store the image filename extension       $this->imageExtension = strtolower( strrchr( $epitome['name'], '.' ) );        // Shop the image        $tempFilename = trim( $image['tmp_name'] );         if ( is_uploaded_file ( $tempFilename ) ) {         if ( !( move_uploaded_file( $tempFilename, $this->getImagePath() ) ) ) trigger_error( "Article::storeUploadedImage(): Couldn't move uploaded file.", E_USER_ERROR );         if ( !( chmod( $this->getImagePath(), 0666 ) ) ) trigger_error( "Commodity::storeUploadedImage(): Couldn't fix permissions on uploaded file.", E_USER_ERROR );       }        // Get the epitome size and type       $attrs = getimagesize ( $this->getImagePath() );       $imageWidth = $attrs[0];       $imageHeight = $attrs[1];       $imageType = $attrs[2];        // Load the image into retention       switch ( $imageType ) {         instance IMAGETYPE_GIF:           $imageResource = imagecreatefromgif ( $this->getImagePath() );           break;         example IMAGETYPE_JPEG:           $imageResource = imagecreatefromjpeg ( $this->getImagePath() );           pause;         example IMAGETYPE_PNG:           $imageResource = imagecreatefrompng ( $this->getImagePath() );           pause;         default:           trigger_error ( "Commodity::storeUploadedImage(): Unhandled or unknown image type ($imageType)", E_USER_ERROR );       }        // Re-create and resize the image to create the thumbnail       $thumbHeight = intval ( $imageHeight / $imageWidth * ARTICLE_THUMB_WIDTH );       $thumbResource = imagecreatetruecolor ( ARTICLE_THUMB_WIDTH, $thumbHeight );       imagecopyresampled( $thumbResource, $imageResource, 0, 0, 0, 0, ARTICLE_THUMB_WIDTH, $thumbHeight, $imageWidth, $imageHeight );        // Save the thumbnail       switch ( $imageType ) {         case IMAGETYPE_GIF:           imagegif ( $thumbResource, $this->getImagePath( IMG_TYPE_THUMB ) );           break;         case IMAGETYPE_JPEG:           imagejpeg ( $thumbResource, $this->getImagePath( IMG_TYPE_THUMB ), JPEG_QUALITY );           interruption;         case IMAGETYPE_PNG:           imagepng ( $thumbResource, $this->getImagePath( IMG_TYPE_THUMB ) );           pause;         default:           trigger_error ( "Article::storeUploadedImage(): Unhandled or unknown image blazon ($imageType)", E_USER_ERROR );       }        $this->update();     }   }     /**   * Deletes any images and/or thumbnails associated with the commodity   */    public function deleteImages() {      // Delete all fullsize images for this article     foreach (glob( ARTICLE_IMAGE_PATH . "/" . IMG_TYPE_FULLSIZE . "/" . $this->id . ".*") equally $filename) {       if ( !unlink( $filename ) ) trigger_error( "Article::deleteImages(): Couldn't delete image file.", E_USER_ERROR );     }          // Delete all thumbnail images for this article     foreach (glob( ARTICLE_IMAGE_PATH . "/" . IMG_TYPE_THUMB . "/" . $this->id . ".*") as $filename) {       if ( !unlink( $filename ) ) trigger_error( "Article::deleteImages(): Couldn't delete thumbnail file.", E_USER_ERROR );     }      // Remove the image filename extension from the object     $this->imageExtension = "";   }     /**   * Returns the relative path to the article's full-size or thumbnail image   *   * @param string The type of image path to call up (IMG_TYPE_FULLSIZE or IMG_TYPE_THUMB). Defaults to IMG_TYPE_FULLSIZE.   * @return cord|false The image's path, or faux if an prototype hasn't been uploaded   */    public role getImagePath( $type=IMG_TYPE_FULLSIZE ) {     return ( $this->id && $this->imageExtension ) ? ( ARTICLE_IMAGE_PATH . "/$blazon/" . $this->id . $this->imageExtension ) : faux;   }     /**   * Returns an Article object matching the given article ID   *   * @param int The article ID   * @render Article|imitation The article object, or false if the record was not constitute or there was a problem   */    public static role getById( $id ) {     $conn = new PDO( DB_DSN, DB_USERNAME, DB_PASSWORD );     $sql = "SELECT *, UNIX_TIMESTAMP(publicationDate) AS publicationDate FROM manufactures WHERE id = :id";     $st = $conn->prepare( $sql );     $st->bindValue( ":id", $id, PDO::PARAM_INT );     $st->execute();     $row = $st->fetch();     $conn = null;     if ( $row ) return new Article( $row );   }     /**   * Returns all (or a range of) Article objects in the DB   *   * @param int Optional The number of rows to return (default=all)   * @render Array|fake A two-element array : results => assortment, a list of Commodity objects; totalRows => Full number of manufactures   */    public static office getList( $numRows=1000000 ) {     $conn = new PDO( DB_DSN, DB_USERNAME, DB_PASSWORD );     $sql = "SELECT SQL_CALC_FOUND_ROWS *, UNIX_TIMESTAMP(publicationDate) As publicationDate FROM articles             Club Past publicationDate DESC LIMIT :numRows";      $st = $conn->prepare( $sql );     $st->bindValue( ":numRows", $numRows, PDO::PARAM_INT );     $st->execute();     $list = array();      while ( $row = $st->fetch() ) {       $article = new Article( $row );       $list[] = $article;     }      // Now get the full number of articles that matched the criteria     $sql = "SELECT FOUND_ROWS() AS totalRows";     $totalRows = $conn->query( $sql )->fetch();     $conn = null;     render ( array ( "results" => $list, "totalRows" => $totalRows[0] ) );   }     /**   * Inserts the current Article object into the database, and sets its ID belongings.   */    public function insert() {      // Does the Article object already have an ID?     if ( !is_null( $this->id ) ) trigger_error ( "Article::insert(): Try to insert an Article object that already has its ID property gear up (to $this->id).", E_USER_ERROR );      // Insert the Article     $conn = new PDO( DB_DSN, DB_USERNAME, DB_PASSWORD );     $sql = "INSERT INTO manufactures ( publicationDate, title, summary, content, imageExtension ) VALUES ( FROM_UNIXTIME(:publicationDate), :championship, :summary, :content, :imageExtension )";     $st = $conn->prepare ( $sql );     $st->bindValue( ":publicationDate", $this->publicationDate, PDO::PARAM_INT );     $st->bindValue( ":title", $this->championship, PDO::PARAM_STR );     $st->bindValue( ":summary", $this->summary, PDO::PARAM_STR );     $st->bindValue( ":content", $this->content, PDO::PARAM_STR );     $st->bindValue( ":imageExtension", $this->imageExtension, PDO::PARAM_STR );     $st->execute();     $this->id = $conn->lastInsertId();     $conn = null;   }     /**   * Updates the current Commodity object in the database.   */    public part update() {      // Does the Article object take an ID?     if ( is_null( $this->id ) ) trigger_error ( "Article::update(): Attempt to update an Article object that does not have its ID property gear up.", E_USER_ERROR );         // Update the Article     $conn = new PDO( DB_DSN, DB_USERNAME, DB_PASSWORD );     $sql = "UPDATE articles SET publicationDate=FROM_UNIXTIME(:publicationDate), title=:title, summary=:summary, content=:content, imageExtension=:imageExtension WHERE id = :id";     $st = $conn->prepare ( $sql );     $st->bindValue( ":publicationDate", $this->publicationDate, PDO::PARAM_INT );     $st->bindValue( ":championship", $this->title, PDO::PARAM_STR );     $st->bindValue( ":summary", $this->summary, PDO::PARAM_STR );     $st->bindValue( ":content", $this->content, PDO::PARAM_STR );     $st->bindValue( ":imageExtension", $this->imageExtension, PDO::PARAM_STR );     $st->bindValue( ":id", $this->id, PDO::PARAM_INT );     $st->execute();     $conn = null;   }     /**   * Deletes the current Article object from the database.   */    public role delete() {      // Does the Commodity object have an ID?     if ( is_null( $this->id ) ) trigger_error ( "Article::delete(): Effort to delete an Article object that does not have its ID property gear up.", E_USER_ERROR );      // Delete the Commodity     $conn = new PDO( DB_DSN, DB_USERNAME, DB_PASSWORD );     $st = $conn->gear up ( "DELETE FROM articles WHERE id = :id LIMIT ane" );     $st->bindValue( ":id", $this->id, PDO::PARAM_INT );     $st->execute();     $conn = null;   }  }  ?>        

Here's a list of the changes nosotros've made to the Article course:

A new $imageExtension property

This corresponds to the imageExtension field you added to the articles table in Step 3. This property is used to shop the filename extension for the commodity's full-size and thumbnail images — for example, ".jpg" or ".png".

We also modified the constructor method, __construct(), to store the new $imageExtension property value in newly-created Article objects.

A new storeUploadedImage() method

We'll call this method from the admin.php script whenever the user uploads a new commodity image using the article edit class. Its job is to move the uploaded paradigm to the fullsize images folder we created in Step 1, also equally generate a thumbnail version of the paradigm and store it in the thumb binder.

The method accepts a single $image parameter. This should be the element in the PHP $_FILES superglobal assortment that contains all the information most the uploaded epitome file.

Here's how the storeUploadedImage() method works:

  1. Check for an upload error
    The kickoff thing the method does is check that the 'error' element in the $image array equals the constant UPLOAD_ERR_OK. This indicates that the user uploaded an prototype, and that the upload was successful. If the upload went OK then the method starts to process the uploaded image; otherwise it does cypher. 
  2. Does the Commodity object accept an ID?
    Assuming the file was uploaded OK, the method so makes sure that the Article object has an ID; in other words, that it has been saved to the database. This is important, considering nosotros're going to rename the epitome file using the article'south ID in a moment, so that nosotros can hands associate the image with the article. If the article doesn't have an ID and so the method calls trigger_error() to display an fault message and leave.
  3. Delete any previous paradigm(s) for this article
    Adjacent the method calls the Commodity::deleteImages() method to delete whatsoever existing full-size and thumbnail image files associated with the article. (We'll write this method in a moment.) Nosotros do this in society to keep the paradigm folders clean, without whatsoever one-time, unused article images lying about. For example, if the article currently has a .png image uploaded, and the user uploads a new .jpg image, nosotros desire to make sure that the now-unused .png images are deleted from the folders.
  4. Get and store the image filename extension
    As you saw before, the $imageExtension property needs to shop the filename extension of the article image. Here the method uses the strrchr() function to extract the filename extension — that is, everything after (and including) the final dot in the filename — and stores the consequence in $imageExtension, converted to lowercase with strtolower() for consistency. 
  5. Store the image
    At present the method moves the actual uploaded image into the images/manufactures/fullsize folder. To do this, it first retrieves the path to the uploaded file from the $_FILES['fieldname']['tmp_name'] array element and stores it in $tempFilename. Typically this value is the path to the uploaded file in the server's temporary folder, such equally /tmp/

    Then the method calls is_uploaded_file() to check that the file in the temporary folder is indeed a file uploaded by PHP. This is a good security precaution to prevent sensitive system files accidentally beingness fabricated public.

    Finally, the method calls the move_uploaded_file() function to motion the uploaded paradigm from the temporary binder to the images/articles/fullsize folder. This part takes two arguments: the path to the file in the temporary folder, and the path to move the file to. Information technology'due south a good idea to use move_uploaded_file() to move uploaded files, since the function performs additional security checks on the file before moving it.

    Once the file's in place, the method calls the chmod() function to set the file'southward permissions to 0666. This ensures that the file can be read and written by anyone, including the spider web server user and whatever FTP user that may need to change or delete the article images. (As always, if you're on a shared web server so you might want to use more restrictive permissions than this.)

  6. Go the image size and blazon
    The next job for storeUploadedImage() is to create the smaller thumbnail version of the uploaded image. Get-go it calls getimagesize(), paassing in the path to the uploaded image, in order to get the prototype'southward width, meridian and format (GIF, JPEG or PNG), which it so stores in $imageWidth, $imageHeight and $imageType respectively.
  7. Load the image into retentiveness
    Now that the method knows the type of image it's dealing with, information technology calls imagecreatefromgif(), imagecreatefromjpeg() or imagecreatefrompng() every bit appropriate to load the prototype into an image resource variable, $imageResource, for processing.
  8. Copy and resize the image to create the thumbnail
    Now it's time to create the thumbnail image. To do this, the method starting time computes the thumbnail top, $thumbHeight, based on the total-size image height ($imageHeight), the full-size epitome width ($imageWidth), and the desired thumbnail width (ARTICLE_THUMB_WIDTH). 

    Adjacent it calls imagecreatetruecolor() to create a blank image resource for storing the thumbnail prototype data, passing in the width and top of the image to create. Information technology stores this resource in a $thumbResource variable.

    Finally, it calls imagecopyresampled() to create the smaller version of the uploaded image and store the effect in the $thumbResource variable. It passes the following arguments to imagecopyresampled():

    • The image resource to store the resized prototype in ($thumbResource)
    • The uploaded image resource ($imageResource)
    • The (x,y) coordinates of top-left corner of the rectangle in $thumbResource to copy the image information to (0,0 — that is, the acme left corner of the thumbnail)
    • The (ten,y) coordinates of pinnacle-left corner of the rectangle in $imageResource to copy the image data from (0,0 — that is, the elevation left corner of the uploaded image)
    • The width and peak of the rectangle in $thumbResource to copy the image data to ( ARTICLE_THUMB_WIDTH and $thumbHeight — that is, the unabridged width and height of the thumbnail)
    • The width and elevation of the rectangle in $imageResource to copy the image data from ( $imageWidth and $imageHeight — that is, the entire width and tiptop of the uploaded image)
  9. Salve the thumbnail
    Now that the method has created the thumbnail image data and stored it in $thumbResource, information technology needs to write the new thumbnail image to disk. To practice this, it calls imagegif(), imagejpeg() or imagepng(), depending on the image type. It passes in both $thumbResource and the path to use for the thumbnail prototype. To get the path, it calls the getImagePath() method (which we'll await at in a moment), passing in our IMG_TYPE_THUMB constant to indicate that we want the path to the thumbnail. 
  10. Update the commodity record
    Finally, since the Article object'due south $imageExtension property may well take changed as a result of uploading the paradigm, the method calls $this->update() to update the commodity tape in the database.

A new deleteImages() method

The deleteImages() method is responsible for clearing out any image files associated with the current article. It'due south called by storeUploadedImage() before uploading a new image (as you saw in the previous department). In addition, it's called if the ambassador specifically asks to delete the article's image and thumbnail via the Edit Commodity grade. Finally, deleteImages() is likewise chosen when the article itself needs to be deleted.

deleteImages() calls PHP's glob() function to retrieve a listing of all image files in both the images/articles/fullsize and images/articles/thumb folders that are named after the article's ID. For instance, if the article'south ID is 3, the call to glob() volition return any prototype files called "iii.gif", "iii.jpg" or "3.png".

For each filename in the array returned past glob(), the method attempts to delete the file by calling PHP's unlink() role. If in that location's a trouble deleting the file and then it raises an error and exits.

Once all the image files have been deleted, deleteImages() sets the Article object's $imageExtension property to an empty string ("") to indicate that the article no longer has an uploaded image.

A new getImagePath() method

The terminal new method we've added to the Article course is getImagePath(), which returns the path to one of the 2 article images.

The method takes a single, optional statement, $type, that indicates whether it should return the path to the total-size paradigm (IMG_TYPE_FULLSIZE, the default), or the thumbnail (IMG_TYPE_THUMB). It so uses the commodity's ID, along with the value stored in the article's $imageExtension property, to compute the path to the prototype file inside the images/manufactures/fullsize or images/articles/thumb folder.

For example, if getImagePath() is passed IMG_TYPE_THUMB as an statement, the commodity's ID is 3, and its $imageExtension property contains ".jpg", so the method will return the value "images/articles/thumb/3.jpg".

Changes to the insert() and update() methods

The final modifications to Article.php are inside the insert() and update() methods toward the end of the file. As you can see, nosotros've modified the SQL INSERT and UPDATE statements to adapt the new $imageExtension property so that the image extension is stored in the articles tabular array. Nosotros've too added extra bindValue() calls to pass the belongings'southward value to the SQL statements.

Step v: Alter the admin.php script

Lock

We at present need to make some changes to admin.php, the back-end admin script, so that it can handle paradigm uploads. Fortunately, we've already washed most of the hard piece of work in our Article class, and then there aren't many changes that we need to make to this script.

Here's the modified admin.php file with the changes highlighted. Supplant the code in your existing cms/admin.php file with this code:

<?php  require( "config.php" ); session_start(); $action = isset( $_GET['action'] ) ? $_GET['activity'] : ""; $username = isset( $_SESSION['username'] ) ? $_SESSION['username'] : "";  if ( $activeness != "login" && $action != "logout" && !$username ) {   login();   exit; }  switch ( $action ) {   case 'login':     login();     break;   case 'logout':     logout();     suspension;   example 'newArticle':     newArticle();     break;   case 'editArticle':     editArticle();     suspension;   case 'deleteArticle':     deleteArticle();     break;   default:     listArticles(); }   role login() {    $results = array();   $results['pageTitle'] = "Admin Login | Widget News";    if ( isset( $_POST['login'] ) ) {      // User has posted the login form: attempt to log the user in      if ( $_POST['username'] == ADMIN_USERNAME && $_POST['password'] == ADMIN_PASSWORD ) {        // Login successful: Create a session and redirect to the admin homepage       $_SESSION['username'] = ADMIN_USERNAME;       header( "Location: admin.php" );      } else {        // Login failed: display an error bulletin to the user       $results['errorMessage'] = "Incorrect username or password. Delight endeavour again.";       crave( TEMPLATE_PATH . "/admin/loginForm.php" );     }    } else {      // User has not posted the login form yet: brandish the form     require( TEMPLATE_PATH . "/admin/loginForm.php" );   }  }   part logout() {   unset( $_SESSION['username'] );   header( "Location: admin.php" ); }   function newArticle() {    $results = array();   $results['pageTitle'] = "New Commodity";   $results['formAction'] = "newArticle";    if ( isset( $_POST['saveChanges'] ) ) {      // User has posted the article edit form: save the new article     $article = new Article;     $commodity->storeFormValues( $_POST );     $article->insert();     if ( isset( $_FILES['epitome'] ) ) $commodity->storeUploadedImage( $_FILES['image'] );     header( "Location: admin.php?status=changesSaved" );    } elseif ( isset( $_POST['abolish'] ) ) {      // User has cancelled their edits: return to the article list     header( "Location: admin.php" );   } else {      // User has not posted the article edit class all the same: display the form     $results['article'] = new Article;     crave( TEMPLATE_PATH . "/admin/editArticle.php" );   }  }   function editArticle() {    $results = array();   $results['pageTitle'] = "Edit Commodity";   $results['formAction'] = "editArticle";    if ( isset( $_POST['saveChanges'] ) ) {      // User has posted the article edit form: salve the article changes      if ( !$article = Article::getById( (int)$_POST['articleId'] ) ) {       header( "Location: admin.php?error=articleNotFound" );       return;     }      $article->storeFormValues( $_POST );     if ( isset($_POST['deleteImage']) && $_POST['deleteImage'] == "yeah" ) $commodity->deleteImages();     $commodity->update();     if ( isset( $_FILES['image'] ) ) $article->storeUploadedImage( $_FILES['image'] );     header( "Location: admin.php?status=changesSaved" );    } elseif ( isset( $_POST['cancel'] ) ) {      // User has cancelled their edits: return to the article list     header( "Location: admin.php" );   } else {      // User has not posted the article edit grade yet: brandish the form     $results['article'] = Article::getById( (int)$_GET['articleId'] );     require( TEMPLATE_PATH . "/admin/editArticle.php" );   }  }   function deleteArticle() {    if ( !$commodity = Article::getById( (int)$_GET['articleId'] ) ) {     header( "Location: admin.php?error=articleNotFound" );     return;   }    $article->deleteImages();   $commodity->delete();   header( "Location: admin.php?status=articleDeleted" ); }   function listArticles() {   $results = array();   $data = Article::getList();   $results['articles'] = $information['results'];   $results['totalRows'] = $data['totalRows'];   $results['pageTitle'] = "All Articles";    if ( isset( $_GET['error'] ) ) {     if ( $_GET['error'] == "articleNotFound" ) $results['errorMessage'] = "Error: Article not found.";   }    if ( isset( $_GET['status'] ) ) {     if ( $_GET['status'] == "changesSaved" ) $results['statusMessage'] = "Your changes have been saved.";     if ( $_GET['status'] == "articleDeleted" ) $results['statusMessage'] = "Article deleted.";   }    require( TEMPLATE_PATH . "/admin/listArticles.php" ); }  ?>        

Let'south work through these changes to admin.php:

  • Changes to newArticle()
    We've added a single line of code to the newArticle() function to handle image uploads. It checks that the 'image' element exists in the $_FILES assortment and, if it does exist, it calls the Commodity object's storeUploadedImage() method, passing in the $_FILES['prototype'] chemical element, to shop the prototype and create the thumbnail. 
  • Changes to editArticle()
    Every bit with newArticle(), we've added a line of code that checks for an uploaded prototype and calls $article->storeUploadedImage() to store it and create the thumbnail. We've too added a line of code that checks if the user selected the "delete image" checkbox in the Edit Article class. If they did then we call $article->deleteImages() to delete whatsoever existing images associated with the article.
  • Changes to deleteArticle()
    Finally, nosotros've added a single line of code to the deleteArticle() function that calls $commodity->deleteImages(). This ensures that any images associated with the article besides go deleted.

Step 6: Alter the front-end templates

Article thumbnails screenshot

Our database and PHP code tin can now handle article images, merely we need to make some changes both to the front-stop templates that visitors meet, and the dorsum-stop admin templates.

Let'south showtime by altering the front-end templates to display the article images.

one. homepage.php

The homepage.php template displays the site'southward abode page, including a listing of recent articles. We'll modify this template to display each article'south thumbnail next to the article in the list.

Hither'southward the modified file with the new lines highlighted — supplant your old cms/templates/homepage.php file with this code:

<?php include "templates/include/header.php" ?>        <ul id="headlines">  <?php foreach ( $results['articles'] as $article ) { ?>          <li>           <h2>             <span class="pubDate"><?php echo date('j F', $article->publicationDate)?></span><a href=".?action=viewArticle&amp;articleId=<?php repeat $article->id?>"><?php echo htmlspecialchars( $article->title )?></a>           </h2>           <p class="summary">             <?php if ( $imagePath = $article->getImagePath( IMG_TYPE_THUMB ) ) { ?>               <a href=".?action=viewArticle&amp;articleId=<?php repeat $article->id?>"><img course="articleImageThumb" src="<?php echo $imagePath?>" alt="Article Thumbnail" /></a>             <?php } ?>           <?php echo htmlspecialchars( $article->summary )?>           </p>         </li>  <?php } ?>        </ul>        <p><a href="./?action=archive">Commodity Annal</a></p>  <?php include "templates/include/footer.php" ?>        

Here we've added some code inside the "summary" paragraph for each article. The lawmaking calls the article'southward getImagePath() method, passing in IMG_TYPE_THUMB to betoken that nosotros desire the path to the article'due south thumbnail. It then stores the path in the $imagePath variable. If this path is a non-false value and then the commodity has a thumbnail image, so the code then constructs a link to view the article, wrapped around an img element that contains the thumbnail's path. We've added an articleImageThumb grade to the thumbnail image so that we can style it in the stylesheet.

If $imagePath's value is false then the article doesn't have a thumbnail, so no markup is constructed.

two. archive.php

archive.php displays the article annal page — that is, a list of all the articles in the database. Nosotros need to modify information technology in the aforementioned way equally homepage.php, so that it displays thumbnails side by side to the article summaries.

Hither'due south the modified archive.php file — replace your old cms/templates/annal.php file with this one:

<?php include "templates/include/header.php" ?>        <h1>Commodity Archive</h1>        <ul id="headlines" grade="archive">  <?php foreach ( $results['manufactures'] as $article ) { ?>          <li>           <h2>             <span class="pubDate"><?php repeat engagement('j F Y', $article->publicationDate)?></span><a href=".?action=viewArticle&amp;articleId=<?php echo $commodity->id?>"><?php echo htmlspecialchars( $commodity->championship )?></a>           </h2>           <p course="summary">             <?php if ( $imagePath = $commodity->getImagePath( IMG_TYPE_THUMB ) ) { ?>               <a href=".?action=viewArticle&amp;articleId=<?php repeat $article->id?>"><img class="articleImageThumb" src="<?php repeat $imagePath?>" alt="Article Thumbnail" /></a>             <?php } ?>           <?php echo htmlspecialchars( $commodity->summary )?>           </p>         </li>  <?php } ?>        </ul>        <p><?php echo $results['totalRows']?> article<?php repeat ( $results['totalRows'] != 1 ) ? 'due south' : '' ?> in full.</p>        <p><a href="./">Return to Homepage</a></p>  <?php include "templates/include/footer.php" ?>        

As y'all can see, this is the same change that we made to homepage.php. If an commodity has an image, its thumbnail volition now announced next to the article summary in the archive page.

3. viewArticle.php

The viewArticle.php template displays an individual article page, containing the commodity's headline, summary and content. Merely as we modified homepage.php and archive.php to display thumbnails next to the article summaries, we also demand to heighten viewArticle.php so that it displays the total-size article images in the article pages.

Here's the changed template. Equally always, I've highlighted the new code. Save this code over your quondam cms/templates/viewArticle.php file:

<?php include "templates/include/header.php" ?>        <h1 style="width: 75%;"><?php echo htmlspecialchars( $results['article']->championship )?></h1>       <div style="width: 75%; font-style: italic;"><?php echo htmlspecialchars( $results['article']->summary )?></div>       <div style="width: 75%; min-height: 300px;">       <?php if ( $imagePath = $results['article']->getImagePath() ) { ?>         <img id="articleImageFullsize" src="<?php echo $imagePath?>" alt="Article Image" />       <?php } ?>       <?php repeat $results['article']->content?>       </div>       <p course="pubDate">Published on <?php echo appointment('j F Y', $results['article']->publicationDate)?></p>        <p><a href="./">Return to Homepage</a></p>  <?php include "templates/include/footer.php" ?>        

This new code works in essentially the same fashion as the code added to the homepage and archive templates. It calls the article's getImagePath() method to go the path to the total-size article paradigm. If the path isn't false then the commodity has an image, and the lawmaking inserts the advisable img element into the markup. The img element is given an id of articleImageFullsize so that we tin can style it using CSS.

Footstep 7: Change the back-stop templates

Edit Article screenshot

There's actually merely one dorsum-end admin template that we need to change, and that'southward the editArticle.php article edit form. Here'due south the new template with changes highlighted — save information technology over your existing cms/templates/admin/editArticle.php file:

<?php include "templates/include/header.php" ?>        <script>        // Prevents file upload hangs in Mac Safari       // Inspired by http://airbladesoftware.com/notes/note-to-cocky-preclude-uploads-hanging-in-safari        function closeKeepAlive() {         if ( /AppleWebKit|MSIE/.test( navigator.userAgent) ) {           var xhr = new XMLHttpRequest();           xhr.open( "Go", "/ping/shut", false );           xhr.send();         }       }        </script>        <div id="adminHeader">         <h2>Widget News Admin</h2>         <p>You are logged in equally <b><?php echo htmlspecialchars( $_SESSION['username']) ?></b>. <a href="admin.php?activeness=logout"?>Log out</a></p>       </div>        <h1><?php echo $results['pageTitle']?></h1>        <form action="admin.php?activeness=<?php repeat $results['formAction']?>" method="post" enctype="multipart/form-data" onsubmit="closeKeepAlive()">         <input type="hidden" name="articleId" value="<?php echo $results['article']->id ?>"/>  <?php if ( isset( $results['errorMessage'] ) ) { ?>         <div form="errorMessage"><?php echo $results['errorMessage'] ?></div> <?php } ?>          <ul>            <li>             <label for="title">Article Title</characterization>             <input blazon="text" proper noun="title" id="title" placeholder="Name of the article" required autofocus maxlength="255" value="<?php echo htmlspecialchars( $results['article']->title )?>" />           </li>            <li>             <label for="summary">Commodity Summary</label>             <textarea name="summary" id="summary" placeholder="Brief description of the article" required maxlength="chiliad" style="top: 5em;"><?php repeat htmlspecialchars( $results['commodity']->summary )?></textarea>           </li>            <li>             <label for="content">Commodity Content</label>             <textarea name="content" id="content" placeholder="The HTML content of the commodity" required maxlength="100000" style="peak: 30em;"><?php repeat htmlspecialchars( $results['commodity']->content )?></textarea>           </li>            <li>             <label for="publicationDate">Publication Appointment</label>             <input type="date" proper name="publicationDate" id="publicationDate" placeholder="YYYY-MM-DD" required maxlength="10" value="<?php repeat $results['article']->publicationDate ? date( "Y-m-d", $results['article']->publicationDate ) : "" ?>" />           </li>            <?php if ( $results['article'] && $imagePath = $results['article']->getImagePath() ) { ?>           <li>             <label>Current Epitome</label>             <img id="articleImage" src="<?php echo $imagePath ?>" alt="Article Image" />           </li>            <li>             <label></label>             <input type="checkbox" name="deleteImage" id="deleteImage" value="yes"/ > <label for="deleteImage">Delete</label>           </li>           <?php } ?>            <li>             <label for="epitome">New Epitome</label>             <input type="file" proper name="image" id="paradigm" placeholder="Choose an epitome to upload" maxlength="255" />           </li>          </ul>          <div class="buttons">           <input type="submit" name="saveChanges" value="Save Changes" />           <input blazon="submit" formnovalidate proper noun="cancel" value="Cancel" />         </div>        </form>  <?php if ( $results['article']->id ) { ?>       <p><a href="admin.php?action=deleteArticle&amp;articleId=<?php repeat $results['commodity']->id ?>" onclick="render ostend('Delete This Article?')">Delete This Article</a></p> <?php } ?>  <?php include "templates/include/footer.php" ?>        

Permit'due south take a wait at each of these changes in turn:

  • The closeKeepAlive() JavaScript function
    For some reason, Safari on the Mac has suffered from a long-standing issue whereby file uploads hang occasionally. (Detect out more near this result hither and here.) Since this is quite abrasive if you lot employ Safari (equally I do), I've added this fiddling function that makes an Ajax request to a non-existent URL on the server, forcing Safari to close its connection to the server. This seems to fix the problem. My function is similar to this script, except that my part doesn't require the Paradigm.js library.
  • Changes to the <class> tag
    Nosotros've added the attribute enctype="multipart/form-data" to the form element. This attribute is required whenever you create a form containing a file upload field. It lets the browser know that it needs to encode the form data as a multipart MIME stream containing different media types (in this case, text and image data). 

    We've likewise attached the closeKeepAlive() role as a submit event handler to the form, so that the function runs when the form is submitted.

  • The article image and "delete" checkbox
    The next addition to the class displays the full-size paradigm currently associated with the article (if whatever). Every bit with the front-stop templates, the PHP code calls the article's getImagePath() method to remember the prototype's path. If an image path was returned, we add an li chemical element to the page containing a field label ("Current Image"), forth with an img element linking to the image. We also include another li element containing a deleteImage checkbox. This lets the administrator delete any image(s) currently associated with the article.
  • The image upload field
    Last, simply by no means least, we add the <input type="file"> upload field that allows the administrator to upload an image for this article. We requite it a name aspect of "image", which means that we're able to access the uploaded file from our PHP lawmaking using $_FILES['image'] (see Step 4 earlier in the tutorial).

Stride viii: Change the stylesheet

Next we'll make some additions and changes to our CMS's stylesheet, way.css, in society to style the commodity images and thumbnails on the front end, as well equally the new elements in the Edit Article form.

Hither's the new way.css file with the changes highlighted. Supervene upon your existing fashion.css file in your cms binder with this file:

/* Mode the body and outer container */  body {   margin: 0;   color: #333;   background-color: #00a0b0;   font-family unit: "Trebuchet MS", Arial, Helvetica, sans-serif;   line-elevation: i.5em; }  #container {   width: 960px;   background: #fff;   margin: 20px machine;   padding: 20px;   -moz-border-radius: 5px;   -webkit-border-radius: 5px;   edge-radius: 5px; }   /* The logo and footer */  #logo {   display: cake;   width: 300px;   padding: 0 660px 20px 0;   edge: none;   edge-lesser: 1px solid #00a0b0;   margin-lesser: 40px; }  #footer {   border-summit: 1px solid #00a0b0;   margin-top: 40px;   padding: 20px 0 0 0;   font-size: .8em; }   /* Headings */  h1 {   color: #eb6841;   margin-bottom: 30px;   line-height: 1.2em; }  h2, h2 a {   color: #edc951; }  h2 a {   text-decoration: none; }   /* Commodity headlines */  #headlines {   list-way: none;   padding-left: 0;   width: 75%; }  #headlines li {   margin-bottom: 2em;   overflow: hidden; }  .pubDate {   font-size: .8em;   color: #eb6841;   text-transform: upper-case letter; }  #headlines .pubDate {   display: inline-cake;   width: 100px;   font-size: .5em;   vertical-align: middle; }  #headlines.archive .pubDate {   width: 130px; }  #headlines .articleImageThumb {   width: 120px;   bladder: left;   margin: 4px 20px 0 0;   edge: 1px solid #00a0b0; }  .summary {   padding-left: 100px; }  #headlines.annal .summary {   padding-left: 130px; }   /* Commodity pages */  #articleImageFullsize {   width: 250px;   float: left;   margin: 4px 20px 10px 0;   border: 1px solid #00a0b0; }   /* "You are logged in..." header on admin pages */  #adminHeader {   width: 940px;   padding: 0 10px;   border-lesser: 1px solid #00a0b0;   margin: -30px 0 40px 0;   font-size: 0.8em; }   /* Style the grade with a coloured groundwork, forth with curved corners and a drop shadow */  form {   margin: 20px auto;   padding: 40px 20px;   overflow: car;   background: #fff4cf;   border: 1px solid #666;   -moz-border-radius: 5px;   -webkit-edge-radius: 5px;     border-radius: 5px;   -moz-box-shadow: 0 0 .5em rgba(0, 0, 0, .8);   -webkit-box-shadow: 0 0 .5em rgba(0, 0, 0, .8);   box-shadow: 0 0 .5em rgba(0, 0, 0, .8); }   /* Give course elements consistent margin, padding and line height */  form ul {   list-style: none;   margin: 0;   padding: 0;   overflow: subconscious; }  course ul li {   margin: .9em 0 0 0;   padding: 0; }  form * {   line-height: 1em; }   /* The field labels */  label {   brandish: block;   float: left;   articulate: left;   text-align: right;   width: xv%;   padding: .4em 0 0 0;   margin: .15em .5em 0 0; }   /* The fields */  input, select, textarea {   display: block;   margin: 0;   padding: .4em;   width: 80%; }  input, textarea, .engagement {   border: 2px solid #666;   -moz-edge-radius: 5px;   -webkit-border-radius: 5px;       border-radius: 5px;   background: #fff; }  input {   font-size: .9em; }  input[type="checkbox"] {   brandish: inline-block;   padding: 0;   margin: 0 0 .8em 0;   width: auto; }  select {   padding: 0;   margin-bottom: 2.5em;   position: relative;   top: .7em; }  textarea {   font-family: "Trebuchet MS", Arial, Helvetica, sans-serif;   font-size: .9em;   height: 5em;   line-height: one.5em; }  textarea#content {   font-family: "Courier New", courier, stock-still; }  #articleImage {   edge: 2px solid #666; }  #deleteImage {   clear: both; }  label[for="deleteImage"] {   bladder: none;   display: inline; }  input[type="file"] {   float: left; }     /* Identify a edge around focused fields */  form *:focus {   border: 2px solid #7c412b;   outline: none; }   /* Display correctly filled-in fields with a dark-green groundwork */  input:valid, textarea:valid {   groundwork: #efe; }   /* Submit buttons */  .buttons {   text-marshal: middle;   margin: 40px 0 0 0; }  input[type="submit"] {   display: inline;   margin: 0 20px;   width: 12em;   padding: 10px;   border: 2px solid #7c412b;   -moz-border-radius: 5px;   -webkit-border-radius: 5px;     border-radius: 5px;   -moz-box-shadow: 0 0 .5em rgba(0, 0, 0, .8);   -webkit-box-shadow: 0 0 .5em rgba(0, 0, 0, .8);   box-shadow: 0 0 .5em rgba(0, 0, 0, .8);   colour: #fff;   background: #ef7d50;   font-weight: bold;   -webkit-appearance: none; }  input[type="submit"]:hover, input[type="submit"]:active {   cursor: pointer;   groundwork: #fff;   colour: #ef7d50; }  input[type="submit"]:active {   background: #eee;   -moz-box-shadow: 0 0 .5em rgba(0, 0, 0, .8) inset;   -webkit-box-shadow: 0 0 .5em rgba(0, 0, 0, .8) inset;   box-shadow: 0 0 .5em rgba(0, 0, 0, .8) inset; }   /* Tables */  tabular array {   width: 100%;   border-plummet: collapse; }  tr, th, td {   padding: 10px;   margin: 0;   text-marshal: left; }  table, th {   border: 1px solid #00a0b0; }  thursday {   border-left: none;   edge-correct: none;   background: #ef7d50;   color: #fff;   cursor: default; }  tr:nth-child(odd) {   background: #fff4cf; }  tr:nth-child(even) {   groundwork: #fff; }  tr:hover {   groundwork: #ddd;   cursor: arrow; }   /* Status and fault boxes */  .statusMessage, .errorMessage {   font-size: .8em;   padding: .5em;   margin: 2em 0;   -moz-edge-radius: 5px;   -webkit-border-radius: 5px;   border-radius: 5px;    -moz-box-shadow: 0 0 .5em rgba(0, 0, 0, .viii);   -webkit-box-shadow: 0 0 .5em rgba(0, 0, 0, .8);   -box-shadow: 0 0 .5em rgba(0, 0, 0, .8); }  .statusMessage {   background-color: #2b2;   border: 1px solid #080;   color: #fff; }  .errorMessage {   groundwork-color: #f22;   border: 1px solid #800;   color: #fff; }        

Equally you can see, we've added various rulesets to manner the thumbnails in the homepage and annal pages; the full-size images in commodity pages; and the "delete image" checkbox, article image and file upload field inside the "Edit Article" form (which you added in Step 7).

On line 89, we've set the thumbnail width to 120 pixels to friction match the ARTICLE_THUMB_WIDTH setting in config.php. Similarly, on line 107 nosotros've ready the width of the full-size images in the article pages to 250 pixels. If yous want to employ dissimilar widths for the thumbnails and images so yous demand to modify these two values, as well as the ARTICLE_THUMB_WIDTH setting.

Try it out!

Slap-up stuff! You now take a CMS that tin can handle prototype uploads. To test your new CMS, follow these steps:

  1. Log in
    Open your browser and visit the base URL of your CMS — for case, http://localhost/cms/. Click the Site Admin link in the footer, and log in.
  2. Upload some images
    Click an article in the All Articles listing, or add together a new article by clicking the Add a New Article link at the bottom of the folio. In the New Commodity / Edit Article grade, click the push button next to the New Paradigm label at the bottom of the form. Choose a file to upload, and then click Save Changes to save your commodity edits and upload the paradigm.
  3. View your images
    Click the Widget News logo at the superlative of the page to view the site. You should meet thumbnail images next to the manufactures in the list. If y'all click the Article Archive link at the bottom of the page then you should too run into the thumbnails there. Click a thumbnail (or article headline) to view the total commodity page, along with the full-size article prototype.
  4. Changing and deleting images
    Only to brand sure everything works, try editing an commodity with an image and uploading a new image. This should then supplant the previous article prototype and thumbnail. (Depending on your server and browser setup, you may demand to clear your browser's enshroud and reload the page to see the new image.) You lot can likewise attempt clicking the Delete checkbox to remove an existing image from an article.

Y'all tin can too try out the demo on our server too! The demo is read-but, so y'all can't upload or delete images, but you can see how the images expect on the front end-finish, likewise as in the back-end article edit class.

Summary

In this tutorial nosotros've added an image upload characteristic to the content direction system from my original tutorial. Here's what we did:

  • Created some folders within your CMS to store the article images and thumbnails
  • Added some constants to the config file to specify the path to the images binder, the width to use for commodity thumbnails, and other useful settings
  • Modified the MySQL database to add an imageExtension field, which tracks the filename extension of the image uploaded for each article
  • Modified the Commodity class to add the $imageExtension property, besides as methods to handle image uploads, image deletion, and retrieving image paths
  • Extended the admin.php admin script to let uploading and deleting of article images
  • Contradistinct the front-end templates, homepage.php, archive.php and viewArticle.php, to display the article thumbnails and full-size images equally appropriate
  • Enhanced the commodity edit grade, editArticle.php, to include the prototype upload field, every bit well as the currently-uploaded prototype and a "delete" image" checkbox, and
  • Tweaked the stylesheet, manner.css, to style the article images and thumbnails, every bit well as the article edit form elements.

Yous tin can now utilize your CMS to publish articles illustrated with images. At present all yous need to exercise is create some beautiful images! Savor. 🙂

[Flickr photo credits for sample images: Man of affairs, Cogs, Willy Wonka, Newspapers, Dollars.]

belewshormilt.blogspot.com

Source: https://www.elated.com/add-image-uploading-to-your-cms/

0 Response to "Prevent Anytthing but Img Being Uploaded Php"

Post a Comment

Iklan Atas Artikel

Iklan Tengah Artikel 1

Iklan Tengah Artikel 2

Iklan Bawah Artikel