Index of Upload Image Share Com Pimpandhost 40

17 May 2019: This commodity 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 simple but useful content management system with PHP and MySQL. I as well showed how to extend the CMS to allow commodity categories.

In this tutorial, you'll expect at another way to extend the CMS. You'll take the original CMS code, and modify information technology then that the ambassador can upload an image for each article. Then, when a visitor views an commodity folio, the CMS will brandish the prototype at the showtime of the commodity. In addition, our CMS will generate a smaller thumbnail version of each article image, and brandish this thumbnail next to each article headline in the homepage and article archive pages.

You can see the finished result past clicking the View Demo link to a higher place. Observe the thumbnail images next to each article headline. Click a headline or thumbnail to view the corresponding commodity, along with the full-size article paradigm.

The programme

We'll first with the original CMS code from Build a CMS in an Afternoon with PHP and MySQL, and modify information technology to include the prototype upload characteristic. Hither are the steps we'll need to behave out:

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

Ready? Let'due south go started!

Step i: Create the image folders

The get-go thing to do is create a couple of folders in your website to store the total-size and thumbnail commodity images.

Open up the existing cms folder and yous'll see an images folder containing the sample logo.jpg prototype. Within this images folder, create an manufactures folder. And then, inside the manufactures folder, create two more folders:

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

Next you lot demand to give your spider web server user permission to create files in these two folders. Typically on a Linux or Mac system, you demand to modify the permissions to 777, similar this:

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

If your CMS is on a remote web server and so you tin unremarkably prepare 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 the config.php file in the tiptop-level cms binder, and add the new lines highlighted in the code below:

<?php ini_set( "display_errors", true ); date_default_timezone_set( "Australia/Sydney" );  // http://www.php.internet/manual/en/timezones.php ascertain( "DB_DSN", "mysql:host=localhost;dbname=cms" ); ascertain( "DB_USERNAME", "username" ); define( "DB_PASSWORD", "password" ); ascertain( "CLASS_PATH", "classes" ); define( "TEMPLATE_PATH", "templates" ); ascertain( "HOMEPAGE_NUM_ARTICLES", v ); define( "ADMIN_USERNAME", "admin" ); define( "ADMIN_PASSWORD", "mypass" ); define( "ARTICLE_IMAGE_PATH", "images/manufactures" ); define( "IMG_TYPE_FULLSIZE", "fullsize" ); ascertain( "IMG_TYPE_THUMB", "thumb" ); ascertain( "ARTICLE_THUMB_WIDTH", 120 ); define( "JPEG_QUALITY", 85 ); crave( CLASS_PATH . "/Commodity.php" );  function handleException( $exception ) {   echo "Distressing, a problem occurred. Please try 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 binder. (If you lot want to shop your article images somewhere else, change this constant appropriately.)
  • IMG_TYPE_FULLSIZE defines a constant to represent the "full-size" paradigm blazon. We'll apply this in the code whenever we want to indicate a total-size image. This value ("fullsize") is also used to locate the full-size images folder (images/articles/fullsize), and then if you apply a unlike binder name, you'll want to update this constant too.
  • IMG_TYPE_THUMB does a similar job to IMG_TYPE_FULLSIZE, but represents the "thumbnail" image type instead.
  • ARTICLE_THUMB_WIDTH defines the width to utilise for the article thumbnail images, in pixels. Our image-handling code 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 (merely largest file size). 85 is a good compromise.

Step three: Modify the database

Safe

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

DROP TABLE IF EXISTS manufactures; CREATE Tabular array articles (   id              smallint unsigned Non NULL auto_increment,   publicationDate date Not NULL,                              # When the article was published   title           varchar(255) NOT Naught,                      # Full championship of the article   summary         text Not Aught,                              # A curt summary of the article   content         mediumtext NOT NULL,                        # The HTML content of the commodity   imageExtension  varchar(255) Not NULL,                      # The filename extension of the article's total-size and thumbnail images    PRIMARY Central     (id) );        

This line adds a new field called imageExtension to the manufactures table. This field stores the filename extension of each commodity's uploaded image. For instance, if the ambassador uploads a PNG paradigm and then we'll shop the value ".png" in the imageExtension field.

What if you lot already take articles in your CMS?

If you load the above tables.sql file into MySQL and then information technology will delete any existing articles table 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 want.

So if y'all already accept articles in your CMS database, you desire to modify the articles table while retaining the existing data in the tabular array. To do this, alter your tables.sql file to the following:

Change TABLE articles ADD imageExtension varchar(255) NOT Zippo AFTER content;        

Applying the changes

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

To check that your changes have been made, get-go login to MySQL:

mysql -u username -p cms

And then use the SHOW TABLES and Explicate commands to check your table schemas in MySQL:

                      mysql> show tables; +---------------+ | Tables_in_cms | +---------------+ | articles      | +---------------+ one row in set (0.00 sec)   mysql> explain manufactures; +-----------------+----------------------+------+-----+---------+----------------+ | Field           | Blazon                 | Null | Key | Default | Extra          | +-----------------+----------------------+------+-----+---------+----------------+ | id              | smallint(5) unsigned | NO   | PRI | Nothing    | auto_increment | | publicationDate | engagement                 | NO   |     | Cipher    |                | | championship           | varchar(255)         | NO   |     | Goose egg    |                | | summary         | text                 | NO   |     | Cypher    |                | | content         | mediumtext           | NO   |     | NULL    |                | | imageExtension  | varchar(255)         | NO   |     | NULL    |                | +-----------------+----------------------+------+-----+---------+----------------+ 6 rows in fix (0.00 sec)  mysql>                  

Detect the new imageExtension field within the manufactures table.

You've ready up your CMS database so that it'south ready to handle image uploads. Now you tin can start modifying the CMS code.

Footstep 4: Modify the Article class

Cogs

Adjacent, we need to change the Article form to handle article images. Hither's the updated Article.php grade file. I've highlighted the lines of code so you tin can run across what's been added and changed. Replace the lawmaking in your existing cms/classes/Article.php file with this new code:

<?php  /**  * Class to handle articles  */  class Article {   // Properties    /**   * @var int The article ID from the database   */   public $id = null;    /**   * @var int When the article is to be / was commencement published   */   public $publicationDate = null;    /**   * @var string Full title of the article   */   public $title = cipher;    /**   * @var string A short summary of the article   */   public $summary = zip;    /**   * @var string The HTML content of the article   */   public $content = aught;    /**   * @var string The filename extension of the article'south full-size and thumbnail images (empty string means the article has no image)   */   public $imageExtension = "";     /**   * Sets the object'south properties using the values in the supplied assortment   *   * @param assoc The property values   */    public function __construct( $data=array() ) {     if ( isset( $information['id'] ) ) $this->id = (int) $information['id'];     if ( isset( $information['publicationDate'] ) ) $this->publicationDate = (int) $information['publicationDate'];     if ( isset( $data['championship'] ) ) $this->title = preg_replace ( "/[^\.\,\-\_\'\"\@\?\!\:\$ a-zA-Z0-9()]/", "", $data['title'] );     if ( isset( $data['summary'] ) ) $this->summary = preg_replace ( "/[^\.\,\-\_\'\"\@\?\!\:\$ a-zA-Z0-ix()]/", "", $data['summary'] );     if ( isset( $data['content'] ) ) $this->content = $data['content'];     if ( isset( $data['imageExtension'] ) ) $this->imageExtension = preg_replace ( "/[^\.\,\-\_\'\"\@\?\!\$ a-zA-Z0-ix()]/", "", $information['imageExtension'] );   }     /**   * Sets the object's backdrop using the edit form post values in the supplied array   *   * @param assoc The course post values   */    public function storeFormValues( $params ) {      // Store all the parameters     $this->__construct( $params );      // Parse and store the publication engagement     if ( isset($params['publicationDate']) ) {       $publicationDate = explode ( '-', $params['publicationDate'] );        if ( count($publicationDate) == iii ) {         list ( $y, $k, $d ) = $publicationDate;         $this->publicationDate = mktime ( 0, 0, 0, $thousand, $d, $y );       }     }   }     /**   * Stores any paradigm uploaded from the edit class   *   * @param assoc The 'image' element from the $_FILES array containing the file upload information   */    public role storeUploadedImage( $image ) {      if ( $image['fault'] == UPLOAD_ERR_OK )     {       // Does the Article object take an ID?       if ( is_null( $this->id ) ) trigger_error( "Article::storeUploadedImage(): Attempt to upload an prototype for an Article object that does non have its ID property set.", E_USER_ERROR );        // Delete any previous image(s) for this article       $this->deleteImages();        // Go and store the image filename extension       $this->imageExtension = strtolower( strrchr( $image['proper name'], '.' ) );        // Store the image        $tempFilename = trim( $paradigm['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( "Article::storeUploadedImage(): Couldn't set up permissions on uploaded file.", E_USER_ERROR );       }        // Get the prototype size and blazon       $attrs = getimagesize ( $this->getImagePath() );       $imageWidth = $attrs[0];       $imageHeight = $attrs[1];       $imageType = $attrs[ii];        // Load the paradigm into memory       switch ( $imageType ) {         case IMAGETYPE_GIF:           $imageResource = imagecreatefromgif ( $this->getImagePath() );           break;         instance IMAGETYPE_JPEG:           $imageResource = imagecreatefromjpeg ( $this->getImagePath() );           intermission;         case IMAGETYPE_PNG:           $imageResource = imagecreatefrompng ( $this->getImagePath() );           break;         default:           trigger_error ( "Article::storeUploadedImage(): Unhandled or unknown image type ($imageType)", E_USER_ERROR );       }        // Copy 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 );        // Relieve 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 );           break;         case IMAGETYPE_PNG:           imagepng ( $thumbResource, $this->getImagePath( IMG_TYPE_THUMB ) );           break;         default:           trigger_error ( "Article::storeUploadedImage(): Unhandled or unknown image type ($imageType)", E_USER_ERROR );       }        $this->update();     }   }     /**   * Deletes any images and/or thumbnails associated with the article   */    public function deleteImages() {      // Delete all fullsize images for this commodity     foreach (glob( ARTICLE_IMAGE_PATH . "/" . IMG_TYPE_FULLSIZE . "/" . $this->id . ".*") equally $filename) {       if ( !unlink( $filename ) ) trigger_error( "Article::deleteImages(): Couldn't delete epitome 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 epitome filename extension from the object     $this->imageExtension = "";   }     /**   * Returns the relative path to the commodity's full-size or thumbnail image   *   * @param string The type of epitome path to retrieve (IMG_TYPE_FULLSIZE or IMG_TYPE_THUMB). Defaults to IMG_TYPE_FULLSIZE.   * @return string|faux The image'southward path, or fake if an image hasn't been uploaded   */    public function getImagePath( $type=IMG_TYPE_FULLSIZE ) {     return ( $this->id && $this->imageExtension ) ? ( ARTICLE_IMAGE_PATH . "/$type/" . $this->id . $this->imageExtension ) : false;   }     /**   * Returns an Article object matching the given article ID   *   * @param int The article ID   * @return Article|simulated The article object, or simulated if the tape was not institute or there was a problem   */    public static function getById( $id ) {     $conn = new PDO( DB_DSN, DB_USERNAME, DB_PASSWORD );     $sql = "SELECT *, UNIX_TIMESTAMP(publicationDate) Equally publicationDate FROM articles WHERE id = :id";     $st = $conn->prepare( $sql );     $st->bindValue( ":id", $id, PDO::PARAM_INT );     $st->execute();     $row = $st->fetch();     $conn = nix;     if ( $row ) render 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|simulated A two-element assortment : results => array, a list of Article objects; totalRows => Full number of articles   */    public static function getList( $numRows=meg ) {     $conn = new PDO( DB_DSN, DB_USERNAME, DB_PASSWORD );     $sql = "SELECT SQL_CALC_FOUND_ROWS *, UNIX_TIMESTAMP(publicationDate) AS publicationDate FROM articles             ORDER BY publicationDate DESC LIMIT :numRows";      $st = $conn->prepare( $sql );     $st->bindValue( ":numRows", $numRows, PDO::PARAM_INT );     $st->execute();     $listing = assortment();      while ( $row = $st->fetch() ) {       $article = new Article( $row );       $list[] = $commodity;     }      // Now become the full number of articles that matched the criteria     $sql = "SELECT FOUND_ROWS() Equally totalRows";     $totalRows = $conn->query( $sql )->fetch();     $conn = null;     render ( array ( "results" => $list, "totalRows" => $totalRows[0] ) );   }     /**   * Inserts the current Commodity object into the database, and sets its ID property.   */    public office insert() {      // Does the Article object already accept an ID?     if ( !is_null( $this->id ) ) trigger_error ( "Article::insert(): Endeavour to insert an Article object that already has its ID belongings gear up (to $this->id).", E_USER_ERROR );      // Insert the Commodity     $conn = new PDO( DB_DSN, DB_USERNAME, DB_PASSWORD );     $sql = "INSERT INTO articles ( publicationDate, title, summary, content, imageExtension ) VALUES ( FROM_UNIXTIME(:publicationDate), :title, :summary, :content, :imageExtension )";     $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->execute();     $this->id = $conn->lastInsertId();     $conn = null;   }     /**   * Updates the current Article object in the database.   */    public function update() {      // Does the Article object have an ID?     if ( is_null( $this->id ) ) trigger_error ( "Article::update(): Effort to update an Article object that does not have its ID property ready.", E_USER_ERROR );         // Update the Article     $conn = new PDO( DB_DSN, DB_USERNAME, DB_PASSWORD );     $sql = "UPDATE articles Set up publicationDate=FROM_UNIXTIME(:publicationDate), title=:championship, summary=:summary, content=:content, imageExtension=:imageExtension WHERE id = :id";     $st = $conn->prepare ( $sql );     $st->bindValue( ":publicationDate", $this->publicationDate, PDO::PARAM_INT );     $st->bindValue( ":title", $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 function delete() {      // Does the Article object take an ID?     if ( is_null( $this->id ) ) trigger_error ( "Article::delete(): Attempt to delete an Article object that does non have its ID holding set.", E_USER_ERROR );      // Delete the Article     $conn = new PDO( DB_DSN, DB_USERNAME, DB_PASSWORD );     $st = $conn->gear up ( "DELETE FROM manufactures WHERE id = :id LIMIT 1" );     $st->bindValue( ":id", $this->id, PDO::PARAM_INT );     $st->execute();     $conn = null;   }  }  ?>        

Here's a list of the changes we've made to the Commodity grade:

A new $imageExtension belongings

This corresponds to the imageExtension field you added to the manufactures tabular array in Step 3. This property is used to store the filename extension for the article's total-size and thumbnail images — for instance, ".jpg" or ".png".

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

A new storeUploadedImage() method

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

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

Here'southward how the storeUploadedImage() method works:

  1. Bank check for an upload error
    The start affair 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 image, and that the upload was successful. If the upload went OK then the method starts to process the uploaded image; otherwise it does nothing. 
  2. Does the Article object take an ID?
    Bold the file was uploaded OK, the method and then makes sure that the Commodity object has an ID; in other words, that information technology has been saved to the database. This is important, because we're going to rename the image file using the article'due south ID in a moment, so that nosotros can easily acquaintance the epitome with the article. If the article doesn't have an ID then the method calls trigger_error() to display an error message and exit.
  3. Delete any previous image(south) for this commodity
    Next the method calls the Article::deleteImages() method to delete any existing total-size and thumbnail image files associated with the article. (We'll write this method in a moment.) We do this in club to keep the image folders clean, without whatsoever old, unused article images lying about. For example, if the article currently has a .png image uploaded, and the user uploads a new .jpg image, we desire to brand certain that the at present-unused .png images are deleted from the folders.
  4. Get and shop the image filename extension
    As you saw earlier, the $imageExtension property needs to store the filename extension of the commodity image. Here the method uses the strrchr() office to excerpt the filename extension — that is, everything after (and including) the final dot in the filename — and stores the result in $imageExtension, converted to lowercase with strtolower() for consistency. 
  5. Store the image
    Now the method moves the bodily uploaded image into the images/articles/fullsize binder. 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 as /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 being made public.

    Finally, the method calls the move_uploaded_file() function to move the uploaded image from the temporary folder to the images/articles/fullsize folder. This function takes ii arguments: the path to the file in the temporary folder, and the path to move the file to. Information technology'south a good thought to use move_uploaded_file() to move uploaded files, since the function performs additional security checks on the file before moving information technology.

    Once the file'due south in place, the method calls the chmod() function to ready the file'south permissions to 0666. This ensures that the file can be read and written by anyone, including the web server user and whatsoever FTP user that may demand to alter or delete the article images. (As ever, if you're on a shared web server then you might want to use more than restrictive permissions than this.)

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

    Next information technology calls imagecreatetruecolor() to create a bare image resource for storing the thumbnail image information, passing in the width and height of the image to create. It stores this resources in a $thumbResource variable.

    Finally, it calls imagecopyresampled() to create the smaller version of the uploaded prototype and store the result in the $thumbResource variable. Information technology passes the following arguments to imagecopyresampled():

    • The prototype resource to store the resized image in ($thumbResource)
    • The uploaded epitome resource ($imageResource)
    • The (10,y) coordinates of top-left corner of the rectangle in $thumbResource to copy the image data to (0,0 — that is, the top left corner of the thumbnail)
    • The (x,y) coordinates of top-left corner of the rectangle in $imageResource to copy the paradigm data from (0,0 — that is, the top left corner of the uploaded image)
    • The width and summit of the rectangle in $thumbResource to copy the paradigm data to ( ARTICLE_THUMB_WIDTH and $thumbHeight — that is, the entire width and height of the thumbnail)
    • The width and acme of the rectangle in $imageResource to re-create the paradigm data from ( $imageWidth and $imageHeight — that is, the entire width and meridian of the uploaded image)
  9. Save the thumbnail
    Now that the method has created the thumbnail image information and stored it in $thumbResource, it needs to write the new thumbnail paradigm to disk. To exercise 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 image. To get the path, information technology calls the getImagePath() method (which we'll look at in a moment), passing in our IMG_TYPE_THUMB constant to bespeak that we want the path to the thumbnail. 
  10. Update the article record
    Finally, since the Article object's $imageExtension belongings may well have changed as a result of uploading the image, 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 electric current article. It's called by storeUploadedImage() earlier uploading a new paradigm (every bit you lot saw in the previous section). In addition, it'south called if the administrator specifically asks to delete the article'south image and thumbnail via the Edit Article form. Finally, deleteImages() is too called when the article itself needs to be deleted.

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

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

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

A new getImagePath() method

The final new method we've added to the Commodity class is getImagePath(), which returns the path to one of the two commodity images.

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

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

Changes to the insert() and update() methods

The final modifications to Commodity.php are inside the insert() and update() methods toward the stop of the file. Equally you tin see, nosotros've modified the SQL INSERT and UPDATE statements to conform the new $imageExtension belongings so that the epitome extension is stored in the articles table. We've also added extra bindValue() calls to laissez passer the property'due south value to the SQL statements.

Step 5: Modify the admin.php script

Lock

We at present need to brand some changes to admin.php, the back-end admin script, so that it can handle image uploads. Fortunately, we've already done nigh of the hard work in our Commodity class, so there aren't many changes that we need to make to this script.

Here's the modified admin.php file with the changes highlighted. Replace 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 ( $action != "login" && $action != "logout" && !$username ) {   login();   get out; }  switch ( $action ) {   case 'login':     login();     pause;   case 'logout':     logout();     break;   case 'newArticle':     newArticle();     pause;   case 'editArticle':     editArticle();     interruption;   instance 'deleteArticle':     deleteArticle();     break;   default:     listArticles(); }   office 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 message to the user       $results['errorMessage'] = "Wrong username or password. Please endeavor again.";       require( TEMPLATE_PATH . "/admin/loginForm.php" );     }    } else {      // User has not posted the login form withal: brandish the form     crave( TEMPLATE_PATH . "/admin/loginForm.php" );   }  }   role 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 class: save the new article     $article = new Article;     $article->storeFormValues( $_POST );     $article->insert();     if ( isset( $_FILES['image'] ) ) $commodity->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 commodity edit grade yet: display the form     $results['article'] = new Commodity;     require( TEMPLATE_PATH . "/admin/editArticle.php" );   }  }   function editArticle() {    $results = array();   $results['pageTitle'] = "Edit Article";   $results['formAction'] = "editArticle";    if ( isset( $_POST['saveChanges'] ) ) {      // User has posted the commodity edit form: salve the article changes      if ( !$commodity = Article::getById( (int)$_POST['articleId'] ) ) {       header( "Location: admin.php?error=articleNotFound" );       render;     }      $commodity->storeFormValues( $_POST );     if ( isset($_POST['deleteImage']) && $_POST['deleteImage'] == "aye" ) $article->deleteImages();     $article->update();     if ( isset( $_FILES['epitome'] ) ) $article->storeUploadedImage( $_FILES['paradigm'] );     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 non posted the article edit grade yet: brandish the form     $results['article'] = Article::getById( (int)$_GET['articleId'] );     require( TEMPLATE_PATH . "/admin/editArticle.php" );   }  }   role deleteArticle() {    if ( !$commodity = Article::getById( (int)$_GET['articleId'] ) ) {     header( "Location: admin.php?error=articleNotFound" );     return;   }    $article->deleteImages();   $article->delete();   header( "Location: admin.php?condition=articleDeleted" ); }   office listArticles() {   $results = array();   $data = Article::getList();   $results['articles'] = $data['results'];   $results['totalRows'] = $data['totalRows'];   $results['pageTitle'] = "All Manufactures";    if ( isset( $_GET['fault'] ) ) {     if ( $_GET['error'] == "articleNotFound" ) $results['errorMessage'] = "Error: Commodity not establish.";   }    if ( isset( $_GET['status'] ) ) {     if ( $_GET['status'] == "changesSaved" ) $results['statusMessage'] = "Your changes have been saved.";     if ( $_GET['status'] == "articleDeleted" ) $results['statusMessage'] = "Article deleted.";   }    crave( TEMPLATE_PATH . "/admin/listArticles.php" ); }  ?>        

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

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

Pace 6: Modify the forepart-end templates

Article thumbnails screenshot

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

Let'south start by altering the front end-end templates to brandish the article images.

1. homepage.php

The homepage.php template displays the site's home folio, including a listing of recent articles. Nosotros'll modify this template to display each commodity's thumbnail next to the article in the list.

Here's the modified file with the new lines highlighted — supercede your onetime cms/templates/homepage.php file with this lawmaking:

<?php include "templates/include/header.php" ?>        <ul id="headlines">  <?php foreach ( $results['articles'] as $article ) { ?>          <li>           <h2>             <span grade="pubDate"><?php echo appointment('j F', $commodity->publicationDate)?></span><a href=".?action=viewArticle&amp;articleId=<?php echo $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 echo $article->id?>"><img class="articleImageThumb" src="<?php echo $imagePath?>" alt="Article Thumbnail" /></a>             <?php } ?>           <?php echo htmlspecialchars( $article->summary )?>           </p>         </li>  <?php } ?>        </ul>        <p><a href="./?action=annal">Commodity Annal</a></p>  <?php include "templates/include/footer.php" ?>        

Hither we've added some code inside the "summary" paragraph for each article. The code calls the article's getImagePath() method, passing in IMG_TYPE_THUMB to betoken that nosotros want the path to the article'southward thumbnail. It so stores the path in the $imagePath variable. If this path is a non-simulated value then the article has a thumbnail epitome, so the code then constructs a link to view the article, wrapped around an img element that contains the thumbnail'due south path. Nosotros've added an articleImageThumb form to the thumbnail paradigm then that we tin manner information technology in the stylesheet.

If $imagePath'southward value is fake and so the article doesn't have a thumbnail, so no markup is constructed.

2. archive.php

archive.php displays the article archive page — that is, a list of all the articles in the database. We need to modify it in the same way as homepage.php, then that it displays thumbnails next to the article summaries.

Here'due south the modified archive.php file — supercede your quondam cms/templates/archive.php file with this one:

<?php include "templates/include/header.php" ?>        <h1>Article Archive</h1>        <ul id="headlines" class="archive">  <?php foreach ( $results['articles'] as $commodity ) { ?>          <li>           <h2>             <bridge course="pubDate"><?php echo engagement('j F Y', $article->publicationDate)?></span><a href=".?action=viewArticle&amp;articleId=<?php echo $article->id?>"><?php echo htmlspecialchars( $article->title )?></a>           </h2>           <p class="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( $article->summary )?>           </p>         </li>  <?php } ?>        </ul>        <p><?php echo $results['totalRows']?> commodity<?php echo ( $results['totalRows'] != 1 ) ? 's' : '' ?> in total.</p>        <p><a href="./">Render to Homepage</a></p>  <?php include "templates/include/footer.php" ?>        

As you can see, this is the same alter that nosotros fabricated to homepage.php. If an article has an epitome, its thumbnail will now appear next to the article summary in the annal page.

3. viewArticle.php

The viewArticle.php template displays an individual commodity page, containing the commodity'southward headline, summary and content. Just as we modified homepage.php and archive.php to display thumbnails next to the article summaries, we as well need to raise viewArticle.php so that it displays the full-size article images in the commodity pages.

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

<?php include "templates/include/header.php" ?>        <h1 fashion="width: 75%;"><?php echo htmlspecialchars( $results['article']->title )?></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="Commodity Image" />       <?php } ?>       <?php echo $results['article']->content?>       </div>       <p class="pubDate">Published on <?php echo date('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 style every bit the code added to the homepage and annal templates. Information technology calls the article's getImagePath() method to get the path to the total-size article image. If the path isn't false then the commodity has an image, and the code inserts the appropriate 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: Alter the back-stop templates

Edit Article screenshot

There's actually only ane dorsum-end admin template that we need to change, and that'due south the editArticle.php article edit course. Hither'southward the new template with changes highlighted — save it 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-self-prevent-uploads-hanging-in-safari        part closeKeepAlive() {         if ( /AppleWebKit|MSIE/.test( navigator.userAgent) ) {           var xhr = new XMLHttpRequest();           xhr.open( "GET", "/ping/close", false );           xhr.send();         }       }        </script>        <div id="adminHeader">         <h2>Widget News Admin</h2>         <p>You lot are logged in equally <b><?php echo htmlspecialchars( $_SESSION['username']) ?></b>. <a href="admin.php?action=logout"?>Log out</a></p>       </div>        <h1><?php echo $results['pageTitle']?></h1>        <form action="admin.php?activity=<?php repeat $results['formAction']?>" method="post" enctype="multipart/form-data" onsubmit="closeKeepAlive()">         <input type="hidden" name="articleId" value="<?php repeat $results['article']->id ?>"/>  <?php if ( isset( $results['errorMessage'] ) ) { ?>         <div grade="errorMessage"><?php repeat $results['errorMessage'] ?></div> <?php } ?>          <ul>            <li>             <label for="title">Commodity Title</label>             <input type="text" name="title" id="title" placeholder="Name of the article" required autofocus maxlength="255" value="<?php echo htmlspecialchars( $results['article']->championship )?>" />           </li>            <li>             <characterization for="summary">Commodity Summary</label>             <textarea proper name="summary" id="summary" placeholder="Brief clarification of the article" required maxlength="1000" style="superlative: 5em;"><?php echo htmlspecialchars( $results['commodity']->summary )?></textarea>           </li>            <li>             <characterization for="content">Article Content</label>             <textarea name="content" id="content" placeholder="The HTML content of the article" required maxlength="100000" style="height: 30em;"><?php echo htmlspecialchars( $results['commodity']->content )?></textarea>           </li>            <li>             <characterization for="publicationDate">Publication Date</characterization>             <input type="appointment" name="publicationDate" id="publicationDate" placeholder="YYYY-MM-DD" required maxlength="10" value="<?php echo $results['article']->publicationDate ? date( "Y-m-d", $results['article']->publicationDate ) : "" ?>" />           </li>            <?php if ( $results['article'] && $imagePath = $results['article']->getImagePath() ) { ?>           <li>             <label>Current Image</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 Image</label>             <input type="file" name="paradigm" id="image" placeholder="Choose an epitome to upload" maxlength="255" />           </li>          </ul>          <div form="buttons">           <input type="submit" name="saveChanges" value="Save Changes" />           <input type="submit" formnovalidate name="cancel" value="Cancel" />         </div>        </course>  <?php if ( $results['article']->id ) { ?>       <p><a href="admin.php?activeness=deleteArticle&amp;articleId=<?php repeat $results['commodity']->id ?>" onclick="return confirm('Delete This Article?')">Delete This Article</a></p> <?php } ?>  <?php include "templates/include/footer.php" ?>        

Let's take a look at each of these changes in turn:

  • The closeKeepAlive() JavaScript role
    For some reason, Safari on the Mac has suffered from a long-continuing issue whereby file uploads hang occasionally. (Observe out more about this issue here and here.) Since this is quite annoying if y'all use Safari (as I practise), I've added this little function that makes an Ajax request to a not-existent URL on the server, forcing Safari to shut its connection to the server. This seems to set the problem. My part is similar to this script, except that my office doesn't crave the Prototype.js library.
  • Changes to the <form> tag
    We've added the attribute enctype="multipart/form-data" to the grade 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 paradigm data). 

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

  • The article image and "delete" checkbox
    The adjacent addition to the form displays the full-size image currently associated with the article (if whatsoever). As with the forepart-terminate templates, the PHP code calls the article's getImagePath() method to retrieve the epitome's path. If an prototype path was returned, we add an li chemical element to the folio containing a field label ("Current Epitome"), along with an img chemical 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
    Concluding, but by no means least, we add together the <input type="file"> upload field that allows the administrator to upload an image for this commodity. We give information technology a proper noun attribute of "image", which ways that we're able to admission the uploaded file from our PHP lawmaking using $_FILES['image'] (see Stride four before in the tutorial).

Pace eight: Change the stylesheet

Next we'll make some additions and changes to our CMS's stylesheet, fashion.css, in gild to mode the article images and thumbnails on the front cease, besides as the new elements in the Edit Article form.

Here's the new style.css file with the changes highlighted. Supersede your existing style.css file in your cms folder with this file:

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

Every bit you lot can see, nosotros've added various rulesets to style the thumbnails in the homepage and archive pages; the full-size images in article pages; and the "delete image" checkbox, article image and file upload field inside the "Edit Article" course (which yous added in Footstep 7).

On line 89, we've ready the thumbnail width to 120 pixels to friction match the ARTICLE_THUMB_WIDTH setting in config.php. Similarly, on line 107 we've fix the width of the total-size images in the commodity pages to 250 pixels. If you want to apply dissimilar widths for the thumbnails and images then you demand to change these two values, every bit well as the ARTICLE_THUMB_WIDTH setting.

Try information technology out!

Great stuff! You now take a CMS that can handle image uploads. To test your new CMS, follow these steps:

  1. Log in
    Open your browser and visit the base of operations URL of your CMS — for instance, http://localhost/cms/. Click the Site Admin link in the footer, and log in.
  2. Upload some images
    Click an article in the All Manufactures listing, or add a new article past clicking the Add a New Commodity link at the bottom of the page. In the New Article / Edit Article form, click the button next to the New Image characterization at the bottom of the form. Choose a file to upload, and then click Relieve Changes to salve your article edits and upload the image.
  3. View your images
    Click the Widget News logo at the peak of the page to view the site. You should meet thumbnail images adjacent to the articles in the list. If you click the Article Annal link at the lesser of the folio then you should also run into the thumbnails at that place. Click a thumbnail (or commodity headline) to view the full article page, along with the full-size article image.
  4. Changing and deleting images
    Just to make sure everything works, try editing an article with an image and uploading a new paradigm. This should then supplant the previous article image and thumbnail. (Depending on your server and browser setup, you may demand to clear your browser's cache and reload the folio to see the new image.) You can also effort clicking the Delete checkbox to remove an existing image from an article.

You can also try out the demo on our server too! The demo is read-simply, and so you can't upload or delete images, but yous tin can see how the images await on the front end-cease, too as in the back-cease commodity edit form.

Summary

In this tutorial we've added an paradigm upload characteristic to the content management 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 folder, the width to utilize for article 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 belongings, also as methods to handle prototype uploads, paradigm deletion, and retrieving image paths
  • Extended the admin.php admin script to permit uploading and deleting of article images
  • Altered the forepart-end templates, homepage.php, annal.php and viewArticle.php, to brandish the article thumbnails and full-size images every bit appropriate
  • Enhanced the commodity edit grade, editArticle.php, to include the image upload field, as well as the currently-uploaded image and a "delete" image" checkbox, and
  • Tweaked the stylesheet, style.css, to style the article images and thumbnails, as well every bit the article edit grade elements.

You tin now employ your CMS to publish articles illustrated with images. Now all you need to do is create some beautiful images! Enjoy. 🙂

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

johnsonhistogives.blogspot.com

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

0 Response to "Index of Upload Image Share Com Pimpandhost 40"

Publicar un comentario

Iklan Atas Artikel

Iklan Tengah Artikel 1

Iklan Tengah Artikel 2

Iklan Bawah Artikel