14 May 2019: This article and the code were updated for PHP7 compatibility.
Building a content management system can seem like a daunting task to the novice PHP developer. However, it needn’t be that difficult. In this tutorial I’ll show you how to build a basic, but fully functional, CMS from scratch in just a few hours. Yes, it can be done!
Along the way, you’ll learn how to create MySQL databases and tables; how to work with PHP objects, constants, includes, sessions, and other features; how to separate business logic from presentation; how to make your PHP code more secure, and much more!
Before you begin, check out the finished product by clicking the View Demo link above. (For security reasons this demo is read-only, so you can’t add, change or delete articles.) You can also click the Download Code link above to download the complete PHP code for the CMS, so you can run it on your own server.
The feature list
Our first job is to work out exactly what we want our CMS to do. The CMS will have the following features:
Front end:
- The homepage, listing the 5 most recent articles
- The article listing page, listing all articles
- The “view article” page, letting visitors see a single article
Back end:
- Admin login/logout
- List all articles
- Add a new article
- Edit an existing article
- Delete an existing article
Each article will have an associated headline, summary, and publication date.
Planning it out
Here are the steps we’ll need to follow to create our CMS:
- Create the database
- Create the
articles
database table - Make a configuration file
- Build the
Article
class - Write the front-end
index.php
script - Write the back-end
admin.php
script - Create the front-end templates
- Create the back-end templates
- Create the stylesheet and logo image
Ready? Grab a cup of tea, and let’s get coding!
Step 1: Create the database

The first thing we need to do is create a MySQL database to store our content. You can do this as follows:
- Run the
mysql
client program
Open a terminal window and enter the following:mysql -u username -p
Then enter your MySQL password when prompted.
- Create the database
At themysql>
prompt, type:create database cms;
Then press Enter.
- Quit the
mysql
client program
At themysql>
prompt, type:exit
Then press Enter.
That’s it! You’ve now created a new, empty database, into which you can put your database tables and content.
Step 2: Create the articles
database table
Our simple CMS has just one database table: articles
. This, as you’d imagine, holds all of the articles in the system.
Let’s create the schema for the table. A table’s schema describes the types of data that the table can hold, as well as other information about the table.
Create a text file called tables.sql
somewhere on your hard drive. Add the following code to the file:
DROP TABLE IF EXISTS articles;
CREATE TABLE articles
(
id smallint unsigned NOT NULL auto_increment,
publicationDate date NOT NULL, # When the article was published
title varchar(255) NOT NULL, # Full title of the article
summary text NOT NULL, # A short summary of the article
content mediumtext NOT NULL, # The HTML content of the article
PRIMARY KEY (id)
);
The above code defines the schema for the articles
table. It’s written in SQL, the language used to create and manipulate databases in MySQL (and most other database systems).
Let’s break the above code down a little:
- Create the
articles
tableDROP TABLE IF EXISTS articles
removes any existingarticles
table (and data — be careful!) if it already exists. We do this because we can’t define a table with the same name as an existing table.CREATE TABLE articles ( )
creates the newarticles
table. The stuff inside the parentheses defines the structure of the data within the table, explained below… - Give each article a unique ID
We’re now ready to define our table structure. A table consists of a number of fields (also called columns). Each field holds a specific type of information about each article.
First, we create an
id
field. This has asmallint unsigned
(unsigned small integer) data type, which means it can hold whole numbers from 0 to 65,535. This lets our CMS hold up to 65,535 articles. We also specify theNOT NULL
attribute, which means the field can’t be empty (null) — this makes life easier for us. We also add theauto_increment
attribute, which tells MySQL to assign a new, unique value to an article’sid
field when the article record is created. So the first article will have anid
of 1, the second will have anid
of 2, and so on. We’ll use this unique value as a handle to refer to the article that we want to display or edit in the CMS. - Add the
publicationDate
field
The next line creates thepublicationDate
field, which stores the date that each article was published. This field has a data type ofdate
, which means it can store date values. - Add the
title
field
Next we create thetitle
field to hold each article’s title. It has a data type ofvarchar(255)
, which means it can store a string of up to 255 characters. - Add the
summary
andcontent
fields
The last 2 fields,summary
andcontent
, hold a short summary of the article and the article’s HTML content respectively. summary has atext
data type (which can hold up to 65,535 characters) andcontent
has amediumtext
data type (which can hold up to 16,777,215 characters). - Add the primary key
The last line inside the
CREATE TABLE
statement defines a key for the table. A key is also called an index, and in simple terms it makes it quicker to find data in the table, at the expense of some extra storage space.We make the
id
field aPRIMARY KEY
. Each table can only have a singlePRIMARY KEY
; this is the key that uniquely identifies each record in the table. In addition, by adding this key, MySQL can retrieve an article based on its ID very quickly.
Now that we’ve created our table schema, we need to load it into MySQL to create the table itself. The easiest way to do this is to open up a terminal window and change to the folder containing your tables.sql
file, then run this command:
mysql -u username -p cms < tables.sql
…where username
is your MySQL username. cms
is the name of the database that you created in Step 1.
Enter your password when prompted. MySQL then loads and runs the code in your tables.sql
file, creating the articles
table inside the cms
database.
Step 3: Make a configuration file

Now that you’ve created your database, you’re ready to start writing your PHP code. Let’s start by creating a configuration file to store various useful settings for our CMS. This file will be used by all the script files in our CMS.
First, create a cms
folder somewhere in the local website on your computer, to hold all the files relating to the CMS. If you’re running XAMPP then the local website will be in an htdocs
folder inside your XAMPP folder. Or, if you prefer, you can create a brand new website just for your CMS, and put all the files in that new website’s document root folder.
Inside the cms
folder, create a file called config.php
with the following code:
<?php ini_set( "display_errors", true ); date_default_timezone_set( "Australia/Sydney" ); // http://www.php.net/manual/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", 5 ); define( "ADMIN_USERNAME", "admin" ); define( "ADMIN_PASSWORD", "mypass" ); require( CLASS_PATH . "/Article.php" ); function handleException( $exception ) { echo "Sorry, a problem occurred. Please try later."; error_log( $exception->getMessage() ); } set_exception_handler( 'handleException' ); ?>
Let’s break this file down:
- Display errors in the browser
Theini_set()
line causes error messages to be displayed in the browser. This is good for debugging, but it should be set tofalse
on a live site since it can be a security risk. - Set the timezone
As our CMS will use PHP’sdate()
function, we need to tell PHP our server’s timezone (otherwise PHP generates a warning message). Mine is set to"Australia/Sydney"
— change this value to your local timezone. - Set the database access details
Next we define a constant,DB_DSN
, that tells PHP where to find our MySQL database. Make sure thedbname
parameter matches the name of your CMS database (cms
in this case). We also store the MySQL username and password that are used to access the CMS database in the constantsDB_USERNAME
andDB_PASSWORD
. Set these values to your MySQL username and password. - Set the paths
We set 2 path names in our config file:CLASS_PATH
, which is the path to the class files, andTEMPLATE_PATH
, which is where our script should look for the HTML template files. Both these paths are relative to our top-levelcms
folder. - Set the number of articles to display on the homepage
HOMEPAGE_NUM_ARTICLES
controls the maximum number of article headlines to display on the site homepage. We’ve set this to 5 initially, but if you want more or less articles, just change this value. - Set the admin username and password
TheADMIN_USERNAME
andADMIN_PASSWORD
constants contain the login details for the CMS admin user. Again, you’ll want to change these to your own values. - Include the
Article
class
Since theArticle
class file — which we’ll create next — is needed by all scripts in our application, we include it here. - Create an exception handler
Finally, we definehandleException()
, a simple function to handle any PHP exceptions that might be raised as our code runs. The function displays a generic error message, and logs the actual exception message to the web server’s error log. In particular, this function improves security by handling any PDO exceptions that might otherwise display the database username and password in the page. Once we’ve definedhandleException()
, we set it as the exception handler by calling PHP’sset_exception_handler()
function.
Step 4: Build the Article
class

You’re now ready to build the Article
PHP class. This is the only class in our CMS, and it handles the nitty-gritty of storing articles in the database, as well as retrieving articles from the database. Once we’ve built this class, it will be really easy for our other CMS scripts to create, update, retrieve and delete articles.
Inside your cms
folder, create a classes
folder. Inside that classes
folder, create a new file called Article.php
, and put the following code into it:
<?php /** * Class to handle articles */ class Article { // Properties /** * @var int The article ID from the database */ public $id = null; /** * @var int When the article was published */ public $publicationDate = null; /** * @var string Full title of the article */ public $title = null; /** * @var string A short summary of the article */ public $summary = null; /** * @var string The HTML content of the article */ public $content = null; /** * Sets the object's properties using the values in the supplied array * * @param assoc The property values */ public function __construct( $data=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()]/", "", $data['title'] ); if ( isset( $data['summary'] ) ) $this->summary = preg_replace ( "/[^\.\,\-\_\'\"\@\?\!\:\$ a-zA-Z0-9()]/", "", $data['summary'] ); if ( isset( $data['content'] ) ) $this->content = $data['content']; } /** * Sets the object's properties using the edit form post values in the supplied array * * @param assoc The form post values */ public function 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, $m, $d, $y ); } } } /** * Returns an Article object matching the given article ID * * @param int The article ID * @return Article|false The article object, or false if the record was not found or there was a problem */ public static function getById( $id ) { $conn = new PDO( DB_DSN, DB_USERNAME, DB_PASSWORD ); $sql = "SELECT *, UNIX_TIMESTAMP(publicationDate) AS publicationDate FROM articles 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) * @return Array|false A two-element array : results => array, a list of Article objects; totalRows => Total number of articles */ public static function 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 ORDER BY 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 total number of articles that matched the criteria $sql = "SELECT FOUND_ROWS() AS totalRows"; $totalRows = $conn->query( $sql )->fetch(); $conn = null; return ( array ( "results" => $list, "totalRows" => $totalRows[0] ) ); } /** * Inserts the current Article object into the database, and sets its ID property. */ public function insert() { // Does the Article object already have an ID? if ( !is_null( $this->id ) ) trigger_error ( "Article::insert(): Attempt to insert an Article object that already has its ID property set (to $this->id).", E_USER_ERROR ); // Insert the Article $conn = new PDO( DB_DSN, DB_USERNAME, DB_PASSWORD ); $sql = "INSERT INTO articles ( publicationDate, title, summary, content ) VALUES ( FROM_UNIXTIME(:publicationDate), :title, :summary, :content )"; $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->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(): Attempt to update an Article object that does not have its ID property set.", 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 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( ":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 have an ID? if ( is_null( $this->id ) ) trigger_error ( "Article::delete(): Attempt to delete an Article object that does not have its ID property set.", E_USER_ERROR ); // Delete the Article $conn = new PDO( DB_DSN, DB_USERNAME, DB_PASSWORD ); $st = $conn->prepare ( "DELETE FROM articles WHERE id = :id LIMIT 1" ); $st->bindValue( ":id", $this->id, PDO::PARAM_INT ); $st->execute(); $conn = null; } } ?>
This file is quite long, but it’s fairly simple stuff when you break it down. Let’s take a look at each section of the code:
1. The class definition and properties
First, we begin to define our Article
class with the code:
class Article {
Everything after these lines of code — up until the closing brace at the end of the file — contains the code that makes up the Article
class.
After starting our class definition, we declare the properties of the class: $id
, $publicationDate
, and so on. Each Article
object that we create will store its article data in these properties. You can see that the property names mirror the field names in our articles
database table.
2. The constructor
Next we create the class methods. These are functions that are tied to the class, as well as to objects created from the class. Our main code can call these methods in order to manipulate the data in the Article
objects.
The first method, __construct()
, is the constructor. This is a special method that is called automatically by the PHP engine whenever a new Article
object is created. Our constructor takes an optional $data
array containing the data to put into the new object’s properties. We then populate those properties within the body of the constructor. This gives us a handy way to create and populate an object in one go.
You’ll notice that the method filters the data before it stores them in the properties. The id
and publicationDate
properties are cast to integers using (int)
, since these values should always be integers. The title
and summary
are filtered using a regular expression to only allow a certain range of characters. It’s good security practice to filter data on input like this, only allowing acceptable values and characters through.
We don’t filter the content
property, however. Why? Well, the administrator will probably want to use a wide range of characters, as well as HTML markup, in the article content. If we restricted the range of allowed characters in the content then we would limit the usefulness of the CMS for the administrator.
Normally this could be a security loophole, since a user could insert malicious JavaScript and other nasty stuff in the content. However, since we presumably trust our site administrator — who is the only person allowed to create the content — this is an acceptable tradeoff in this case. If you were dealing with user-generated content, such as comments or forum posts, then you would want to be more careful, and only allow “safe” HTML to be used. A really great tool for this is HTML Purifier, which thoroughly analyses HTML input and removes all potentially malicious code.
3. storeFormValues()
Our next method, storeFormValues()
, is similar to the constructor in that it stores a supplied array of data in the object’s properties. The main difference is that storeFormValues()
can handle data in the format that is submitted via our New Article and Edit Article forms (which we’ll create later). In particular, it can handle publication dates in the format YYYY-MM-DD
, converting the date into the UNIX timestamp format suitable for storing in the object.
The purpose of this method is simply to make it easy for our admin scripts to store the data submitted by the forms. All they have to do is call storeFormValues()
, passing in the array of form data.
4. getById()
Now we come to the methods that actually access the MySQL database. The first of these, getById()
, accepts an article ID argument ($id
), then retrieves the article record with that ID from the articles
table, and stores it in a new Article
object.
Usually, when you call a method, you first create or retrieve an object, then call the method on that object. However, since this method returns a new Article
object, it would be helpful if the method could be called directly by our calling code, and not via an existing object. Otherwise, we would have to create a new dummy object each time we wanted to call the method and retrieve an article.
To enable our method to be called without needing an object, we add the static
keyword to the method definition. This allows the method to be called directly without specifying an object:
public static function getById( $id ) {
The method itself uses PDO to connect to the database, retrieve the article record using a SELECT
SQL statement, and store the article data in a new Article
object, which is then returned to the calling code.
Let’s break this method down:
- Connect to the database
$conn = new PDO( DB_DSN, DB_USERNAME, DB_PASSWORD );
This makes a connection to the MySQL database using the login details from the
config.php
file, and stores the resulting connection handle in$conn
. This handle is used by the remaining code in the method to talk to the database. - Retrieve the article record
$sql = "SELECT *, UNIX_TIMESTAMP(publicationDate) AS publicationDate FROM articles WHERE id = :id"; $st = $conn->prepare( $sql ); $st->bindValue( ":id", $id, PDO::PARAM_INT ); $st->execute(); $row = $st->fetch();
Our
SELECT
statement retrieves all fields (*
) from the record in thearticles
table that matches the givenid
field. It also retrieves thepublicationDate
field in UNIX timestamp format instead of the default MySQL date format, so we can store it easily in our object.Rather than placing our
$id
parameter directly inside theSELECT
string, which can be a security risk, we instead use:id
. This is known as a placeholder. In a minute, we’ll call a PDO method to bind our$id
value to this placeholder.Once we’ve stored our
SELECT
statement in a string, we prepare the statement by calling$conn->prepare()
, storing the resulting statement handle in a$st
variable.We now bind the value of our
$id
variable — that is, the ID of the article we want to retrieve — to our:id
placeholder by calling thebindValue()
method. We pass in the placeholder name; the value to bind to it; and the value’s data type (integer in this case) so that PDO knows how to correctly escape the value.Lastly, we call
execute()
to run the query, then we usefetch()
to retrieve the resulting record as an associative array of field names and corresponding field values, which we store in the$row
variable. - Close the connection
$conn = null;
Since we no longer need our connection, we close it by assigning
null
to the$conn
variable. It’s a good idea to close database connections as soon as possible to free up memory on the server. - Return the new
Article
objectif ( $row ) return new Article( $row ); }
The last thing our method needs to do is create a new
Article
object that stores the record returned from the database, and return this object to the calling code. First it checks that the returned value from thefetch()
call,$row
, does in fact contain data. If it does then it creates a newArticle
object, passing in$row
as it does so. Remember that this calls our constructor that we created earlier, which populates the object with the data contained in the$row
array. We then return this new object, and our work here is done.
5. getList()
Our next method, getList()
, is similar in many ways to getById()
. The main difference, as you might imagine, is that it can retrieve many articles at once, rather than just 1 article. It’s used whenever we need to display a list of articles to the user or administrator.
getList()
accepts an optional argument:
$numRows
- The maximum number of articles to retrieve. We default this value to 1,000,000 (i.e. effectively all articles). This parameter allows us to display, say, just the first 5 articles on the site homepage.
Much of this method’s code is similar to getById()
. Let’s look at a few lines of interest:
$sql = "SELECT SQL_CALC_FOUND_ROWS *, UNIX_TIMESTAMP(publicationDate) AS publicationDate FROM articles
ORDER BY publicationDate DESC LIMIT :numRows";
Our query is a bit more complex than last time. First, notice that there’s no WHERE
clause this time; this is because we want to retrieve all articles, rather than an article that matches a specific ID.
We’ve also added a LIMIT
clause, passing in the $numRows
parameter (as a placeholder), so that we can optionally limit the number of records returned.
Finally, the special MySQL value SQL_CALC_FOUND_ROWS
tells MySQL to return the actual number of records returned; this information is useful for displaying to the user, as well as for other things like pagination of results.
$list = array(); while ( $row = $st->fetch() ) { $article = new Article( $row ); $list[] = $article; }
Since we’re returning multiple rows, we create an array, $list
, to hold the corresponding Article
objects. We then use a while
loop to retrieve the next row via fetch()
, create a new Article
object, store the row values in the object, and add the object to the $list
array. When there are no more rows, fetch()
returns false
and the loop exits.
// Now get the total number of articles that matched the criteria $sql = "SELECT FOUND_ROWS() AS totalRows"; $totalRows = $conn->query( $sql )->fetch(); $conn = null; return ( array ( "results" => $list, "totalRows" => $totalRows[0] ) );
Finally, we run another query that uses the MySQL FOUND_ROWS()
function to get the number of returned rows calculated by our previous SQL_CALC_FOUND_ROWS
command. This time we use the PDO query()
method, which lets us quickly run a query if there are no placeholders to bind. We call fetch()
on the resulting statement handle to retrieve the result row, then return both the list of Article
objects ($list
) and the total row count as an associative array.
6. insert()
The remaining methods in our Article
class deal with adding, changing and deleting article records in the database.
insert()
adds a new article record to the articles
table, using the values stored in the current Article
object:
- First, the method makes sure that the object doesn’t already have its
$id
property set. If it does have an ID then the article presumably already exists in the database, so we shouldn’t try to insert it again. - Then the method runs an SQL
INSERT
query to insert the record into thearticles
table, using placeholders to pass the property values to the database. Note the use of the MySQLFROM_UNIXTIME()
function to convert the publication date from UNIX timestamp format back into MySQL format. - After running the query, the method retrieves the new article record’s ID using the PDO
lastInsertId()
function, and stores it in the object’s$id
property for future reference. Remember that we set up thearticles
table’sid
field as anauto_increment
field, so that MySQL generates a new unique ID for each new article record.
7. update()
This method is similar to insert()
, except that it updates an existing article record in the database instead of creating a new record.
First it checks that the object has an ID, since you can’t update a record without knowing its ID. Then it uses the SQL UPDATE
statement to update the record’s fields. Notice that we pass the object’s ID to the UPDATE
statement so that it knows which record to update.
5. delete()
The delete()
method is pretty self-explanatory. It uses the SQL DELETE
statement to remove the article stored in the object from the articles
table, using the object’s $id
property to identify the record in the table. For safety reasons, we add LIMIT 1
to the query to make sure that only 1 article record can be deleted at a time.
Step 5: Write the front-end index.php
script

We’ve now created our Article
class, which does the heavy lifting for our CMS. Now that’s out of the way, the rest of the code is pretty simple!
First, let’s create index.php
, the script that controls the display of the front-end pages of the site. Save this file in the cms
folder you created earlier, at the start of Step 4:
<?php require( "config.php" ); $action = isset( $_GET['action'] ) ? $_GET['action'] : ""; switch ( $action ) { case 'archive': archive(); break; case 'viewArticle': viewArticle(); break; default: homepage(); } function archive() { $results = array(); $data = Article::getList(); $results['articles'] = $data['results']; $results['totalRows'] = $data['totalRows']; $results['pageTitle'] = "Article Archive | Widget News"; require( TEMPLATE_PATH . "/archive.php" ); } function viewArticle() { if ( !isset($_GET["articleId"]) || !$_GET["articleId"] ) { homepage(); return; } $results = array(); $results['article'] = Article::getById( (int)$_GET["articleId"] ); $results['pageTitle'] = $results['article']->title . " | Widget News"; require( TEMPLATE_PATH . "/viewArticle.php" ); } function homepage() { $results = array(); $data = Article::getList( HOMEPAGE_NUM_ARTICLES ); $results['articles'] = $data['results']; $results['totalRows'] = $data['totalRows']; $results['pageTitle'] = "Widget News"; require( TEMPLATE_PATH . "/homepage.php" ); } ?>
Let’s break this script down:
- Include the config file
The first line of code includes theconfig.php
file we created earlier, so that all the configuration settings are available to the script. We userequire()
rather thaninclude()
;require()
generates an error if the file can’t be found. - Grab the
action
parameterWe store the
$_GET['action']
parameter in a variable called$action
, so that we can use the value later in the script. Before doing this, we check that the$_GET['action']
value exists by usingisset()
. If it doesn’t, we set the corresponding$action
variable to an empty string (""
). - Decide which action to perform
Theswitch
block looks at theaction
parameter in the URL to determine which action to perform (display the archive, or view an article). If noaction
parameter is in the URL then the script displays the site homepage. archive()
This function displays a list of all the articles in the database. It does this by calling thegetList()
method of theArticle
class that we created earlier. The function then stores the results, along with the page title, in a$results
associative array so the template can display them in the page. Finally, it includes the template file to display the page. (We’ll create the templates in a moment.)viewArticle()
This function displays a single article page. It retrieves the ID of the article to display from thearticleId
URL parameter, then calls theArticle
class’sgetById()
method to retrieve the article object, which it stores in the$results
array for the template to use. (If noarticleId
was supplied, or the article couldn’t be found, then the function simply displays the homepage instead.)homepage()
Our last function,homepage()
, displays the site homepage containing a list of up toHOMEPAGE_NUM_ARTICLES
articles (5 by default). It’s much like thearchive()
function, except that it passesHOMEPAGE_NUM_ARTICLES
to thegetList()
method to limit the number of articles returned.
Step 6: Write the back-end admin.php
script

Our admin script is a bit more complex than index.php
, since it deals with all the admin functions for the CMS. The basic structure, though, is similar to index.php
.
Save this file, admin.php
, in the same folder as your index.php
script:
<?php require( "config.php" ); session_start(); $action = isset( $_GET['action'] ) ? $_GET['action'] : ""; $username = isset( $_SESSION['username'] ) ? $_SESSION['username'] : ""; if ( $action != "login" && $action != "logout" && !$username ) { login(); exit; } switch ( $action ) { case 'login': login(); break; case 'logout': logout(); break; case 'newArticle': newArticle(); break; case 'editArticle': editArticle(); break; case 'deleteArticle': deleteArticle(); break; default: listArticles(); } function 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'] = "Incorrect username or password. Please try again."; require( TEMPLATE_PATH . "/admin/loginForm.php" ); } } else { // User has not posted the login form yet: display the form require( TEMPLATE_PATH . "/admin/loginForm.php" ); } } function logout() { unset( $_SESSION['username'] ); header( "Location: admin.php" ); } function newArticle() { $results = array(); $results['pageTitle'] = "New Article"; $results['formAction'] = "newArticle"; if ( isset( $_POST['saveChanges'] ) ) { // User has posted the article edit form: save the new article $article = new Article; $article->storeFormValues( $_POST ); $article->insert(); 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 form yet: display the form $results['article'] = new Article; 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 article edit form: save the article changes if ( !$article = Article::getById( (int)$_POST['articleId'] ) ) { header( "Location: admin.php?error=articleNotFound" ); return; } $article->storeFormValues( $_POST ); $article->update(); 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 form yet: display the form $results['article'] = Article::getById( (int)$_GET['articleId'] ); require( TEMPLATE_PATH . "/admin/editArticle.php" ); } } function deleteArticle() { if ( !$article = Article::getById( (int)$_GET['articleId'] ) ) { header( "Location: admin.php?error=articleNotFound" ); return; } $article->delete(); header( "Location: admin.php?status=articleDeleted" ); } function listArticles() { $results = array(); $data = Article::getList(); $results['articles'] = $data['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’s look at some interesting sections of this script:
- Start a user session
Towards the top of the script we call
session_start()
. This PHP function starts a new session for the user, which we can use to track whether the user is logged in or not. (If a session for this user already exists, PHP automatically picks it up and uses it.) - Grab the
action
parameter andusername
session variable
Next we store the$_GET['action']
parameter in a variable called$action
, and the$_SESSION['username']
session variable in$username
, so that we can use these values later in the script. Before doing this, we check that these values exist by usingisset()
. If a value doesn’t exist then we set the corresponding variable to an empty string (""
). - Check the user is logged in
The user shouldn’t be allowed to do anything unless they’re logged in as an administrator. So the next thing we do is inspect$username
to see if the session contained a value for theusername
key, which we use to signify that the user is logged in. If$username
‘s value is empty — and the user isn’t already trying to log in or out — then we display the login page and exit immediately. - Decide which action to perform
The
switch
block works much like the one inindex.php
: it calls the appropriate function based on the value of theaction
URL parameter. The default action is to display the list of articles in the CMS. login()
This is called when the user needs to log in, or is in the process of logging in.If the user has submitted the login form — which we check by looking for the
login
form parameter — then the function checks the entered username and password against the config valuesADMIN_USERNAME
andADMIN_PASSWORD
. If they match then theusername
session key is set to the admin username, effectively logging them in, and we then redirect the browser back to theadmin.php
script, which then displays the list of articles. If the username and password don’t match then the login form is redisplayed with an error message.If the user hasn’t submitted the login form yet then the function simply displays the form.
logout()
This function is called when the user elects to log out. It simply removes theusername
session key and redirects back toadmin.php
.newArticle()
This function lets the user create a new article. If the user has just posted the “new article” form then the function creates a new
Article
object, stores the form data in the object by callingstoreFormValues()
, inserts the article into the database by callinginsert()
, and redirects back to the article list, displaying a “Changes Saved” status message.If the user has not posted the “new article” form yet then the function creates a new empty
Article
object with no values, then uses theeditArticle.php
template to display the article edit form using this emptyArticle
object.editArticle()
This function is similar to
newArticle()
, except that it lets the user edit an existing article. When the user saves their changes then the function retrieves the existing article usinggetById()
, stores the new values in theArticle
object, then saves the changed object by callingupdate()
. (If the article isn’t found in the database then the function displays an error.)When displaying the article edit form, the function again uses the
getById()
method to load the current article field values into the form for editing.deleteArticle()
If the user has chosen to delete an article then this function first retrieves the article to be deleted (displaying an error if the article couldn’t be found in the database), then calls the article’sdelete()
method to remove the article from the database. It then redirects to the article list page, displaying an “article deleted” status message.listArticles()
The last function inadmin.php
displays a list of all articles in the CMS for editing. The function uses theArticle
class’sgetList()
method to retrieve all the articles, then it uses thelistArticles.php
template to display the list. Along the way, it also checks the URL query parameterserror
andstatus
to see if any error or status message needs to be displayed in the page. If so, then it creates the necessary message and passes it to the template for display.
Step 7: Create the front-end templates

We’ve now created all the PHP code for our CMS’s functionality. The next step is to create the HTML templates for both the front-end and admin pages.
First, the front-end templates.
1. The include files
Create a folder called templates
inside your cms
folder. Now create a folder called include
inside the templates
folder. In this folder we’re going to put the header and footer markup that is common to every page of the site, to save having to put it inside every template file.
Create a new file called header.php
inside your include
folder, with the following code:
<!DOCTYPE html> <html lang="en"> <head> <title><?php echo htmlspecialchars( $results['pageTitle'] )?></title> <link rel="stylesheet" type="text/css" href="style.css" /> </head> <body> <div id="container"> <a href="."><img id="logo" src="images/logo.jpg" alt="Widget News" /></a>
As you can see, this code simply displays the markup to start the HTML page. It uses the $results['pageTitle']
variable passed from the main script (index.php
or admin.php
) to set the title
element, and also links to a stylesheet, style.css
(we’ll create this in a moment).
Next, create a file called footer.php
in the same folder:
<div id="footer"> Widget News © 2011. All rights reserved. <a href="admin.php">Site Admin</a> </div> </div> </body> </html>
This markup finishes off each HTML page in the system.
2. homepage.php
Now go back up to the templates
folder, and create a homepage.php
template file in there, with the following 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&articleId=<?php echo $article->id?>"><?php echo htmlspecialchars( $article->title )?></a> </h2> <p class="summary"><?php echo htmlspecialchars( $article->summary )?></p> </li> <?php } ?> </ul> <p><a href="./?action=archive">Article Archive</a></p> <?php include "templates/include/footer.php" ?>
This template displays the article headlines on the homepage as an unordered list. It loops through the array of Article
objects stored in $results['articles']
and displays each article’s publication date, title, and summary. The title is linked back to '.'
(index.php
), passing action=viewArticle
, as well as the article’s ID, in the URL. This allows the visitor to read an article by clicking its title.
The template also includes a link to the article archive ("./?action=archive"
).
3. archive.php
Now create an archive.php
template file in your templates
folder:
<?php include "templates/include/header.php" ?> <h1>Article Archive</h1> <ul id="headlines" class="archive"> <?php foreach ( $results['articles'] as $article ) { ?> <li> <h2> <span class="pubDate"><?php echo date('j F Y', $article->publicationDate)?></span><a href=".?action=viewArticle&articleId=<?php echo $article->id?>"><?php echo htmlspecialchars( $article->title )?></a> </h2> <p class="summary"><?php echo htmlspecialchars( $article->summary )?></p> </li> <?php } ?> </ul> <p><?php echo $results['totalRows']?> article<?php echo ( $results['totalRows'] != 1 ) ? 's' : '' ?> in total.</p> <p><a href="./">Return to Homepage</a></p> <?php include "templates/include/footer.php" ?>
This template displays the archive of all articles in the CMS. As you can see, it’s almost identical to homepage.php
. It adds an archive
CSS class to the unordered list so we can style the list items a bit differently to the homepage, and it also adds the year to the article publication dates (since the archive might go back a few years).
The page also includes a total count of the articles in the database, retrieved via $results['totalRows']
. Finally, instead of the archive link at the bottom of the page, it includes a “Return to Homepage” link.
4. viewArticle.php
The last front-end template displays an article to the user. Create a file called viewArticle.php
in your templates
folder, and add the following markup:
<?php include "templates/include/header.php" ?> <h1 style="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%;"><?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 template is very straightforward. It displays the selected article’s title, summary and content, as well as its publication date and a link to return to the homepage.
Step 8: Create the back-end templates

Now that we’ve created the templates for the front end of the site, it’s time to create the 3 admin templates.
1. loginForm.php
First, create another folder called admin
inside your templates
folder. Inside the admin
folder, create the first of the 3 templates, loginForm.php
:
<?php include "templates/include/header.php" ?> <form action="admin.php?action=login" method="post" style="width: 50%;"> <input type="hidden" name="login" value="true" /> <?php if ( isset( $results['errorMessage'] ) ) { ?> <div class="errorMessage"><?php echo $results['errorMessage'] ?></div> <?php } ?> <ul> <li> <label for="username">Username</label> <input type="text" name="username" id="username" placeholder="Your admin username" required autofocus maxlength="20" /> </li> <li> <label for="password">Password</label> <input type="password" name="password" id="password" placeholder="Your admin password" required maxlength="20" /> </li> </ul> <div class="buttons"> <input type="submit" name="login" value="Login" /> </div> </form> <?php include "templates/include/footer.php" ?>
This page contains the admin login form, which posts back to admin.php?action=login
. It includes a hidden field, login
, that our login()
function from Step 6 uses to check if the form has been posted. The form also contains an area for displaying any error messages (such as an incorrect username or password), as well as username and password fields and a “Login” button.
2. listArticles.php
Now create the second admin template in your admin
folder. This one’s called listArticles.php
:
<?php include "templates/include/header.php" ?> <div id="adminHeader"> <h2>Widget News Admin</h2> <p>You are logged in as <b><?php echo htmlspecialchars( $_SESSION['username']) ?></b>. <a href="admin.php?action=logout"?>Log out</a></p> </div> <h1>All Articles</h1> <?php if ( isset( $results['errorMessage'] ) ) { ?> <div class="errorMessage"><?php echo $results['errorMessage'] ?></div> <?php } ?> <?php if ( isset( $results['statusMessage'] ) ) { ?> <div class="statusMessage"><?php echo $results['statusMessage'] ?></div> <?php } ?> <table> <tr> <th>Publication Date</th> <th>Article</th> </tr> <?php foreach ( $results['articles'] as $article ) { ?> <tr onclick="location='admin.php?action=editArticle&articleId=<?php echo $article->id?>'"> <td><?php echo date('j M Y', $article->publicationDate)?></td> <td> <?php echo $article->title?> </td> </tr> <?php } ?> </table> <p><?php echo $results['totalRows']?> article<?php echo ( $results['totalRows'] != 1 ) ? 's' : '' ?> in total.</p> <p><a href="admin.php?action=newArticle">Add a New Article</a></p> <?php include "templates/include/footer.php" ?>
This template displays the list of articles for the administrator to edit. After displaying any error or status messages, it loops through the array of Article
objects stored in $results['articles']
, displaying each article’s publication date and title in a table row. It also adds a JavaScript onclick
event to each article’s table row, so that the administrator can click an article to edit it.
The template also includes the total article count, as well as a link to let the administrator add a new article.
3. editArticle.php
Now save the final template, editArticle.php
, in your admin
folder:
<?php include "templates/include/header.php" ?> <div id="adminHeader"> <h2>Widget News Admin</h2> <p>You are logged in as <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?action=<?php echo $results['formAction']?>" method="post"> <input type="hidden" name="articleId" value="<?php echo $results['article']->id ?>"/> <?php if ( isset( $results['errorMessage'] ) ) { ?> <div class="errorMessage"><?php echo $results['errorMessage'] ?></div> <?php } ?> <ul> <li> <label for="title">Article Title</label> <input type="text" name="title" id="title" placeholder="Name of the article" required autofocus maxlength="255" value="<?php echo htmlspecialchars( $results['article']->title )?>" /> </li> <li> <label for="summary">Article Summary</label> <textarea name="summary" id="summary" placeholder="Brief description of the article" required maxlength="1000" style="height: 5em;"><?php echo htmlspecialchars( $results['article']->summary )?></textarea> </li> <li> <label 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['article']->content )?></textarea> </li> <li> <label for="publicationDate">Publication Date</label> <input type="date" 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> </ul> <div class="buttons"> <input type="submit" name="saveChanges" value="Save Changes" /> <input type="submit" formnovalidate name="cancel" value="Cancel" /> </div> </form> <?php if ( $results['article']->id ) { ?> <p><a href="admin.php?action=deleteArticle&articleId=<?php echo $results['article']->id ?>" onclick="return confirm('Delete This Article?')">Delete This Article</a></p> <?php } ?> <?php include "templates/include/footer.php" ?>
This edit form is used both for creating new articles, and for editing existing articles. It posts to either admin.php?action=newArticle
or admin.php?action=editArticle
, depending on the value passed in the $results['formAction']
variable. It also contains a hidden field, articleId
, to track the ID of the article being edited (if any).
The form also includes an area for error messages, as well as fields for the article title, summary, content, and publication date. Finally, there are 2 buttons for saving and cancelling changes, and a link to allow the admin to delete the currently-edited article.
Step 9: Create the stylesheet and logo image
Our CMS application is basically done now, but in order to make it look a bit nicer for both our visitors and the site administrator, we’ll create a CSS file to control the look of the site. Save this file as style.css
in your cms
folder:
/* Style the body and outer container */ body { margin: 0; color: #333; background-color: #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 { display: block; width: 300px; padding: 0 660px 20px 0; border: none; border-bottom: 1px solid #00a0b0; margin-bottom: 40px; } #footer { border-top: 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; } /* Article headlines */ #headlines { list-style: none; padding-left: 0; width: 75%; } #headlines li { margin-bottom: 2em; } .pubDate { font-size: .8em; color: #eb6841; text-transform: uppercase; } #headlines .pubDate { display: inline-block; width: 100px; font-size: .5em; vertical-align: middle; } #headlines.archive .pubDate { width: 130px; } .summary { padding-left: 100px; } #headlines.archive .summary { padding-left: 130px; } /* "You 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, along with curved corners and a drop shadow */ form { margin: 20px auto; padding: 40px 20px; overflow: auto; background: #fff4cf; border: 1px solid #666; -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); } /* Give form elements consistent margin, padding and line height */ form ul { list-style: none; margin: 0; padding: 0; } form ul li { margin: .9em 0 0 0; padding: 0; } form * { line-height: 1em; } /* The field labels */ label { display: block; float: left; clear: left; text-align: right; width: 15%; 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, .date { border: 2px solid #666; -moz-border-radius: 5px; -webkit-border-radius: 5px; border-radius: 5px; background: #fff; } input { font-size: .9em; } 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: 1.5em; } textarea#content { font-family: "Courier New", courier, fixed; } /* Place a border around focused fields */ form *:focus { border: 2px solid #7c412b; outline: none; } /* Display correctly filled-in fields with a green background */ input:valid, textarea:valid { background: #efe; } /* Submit buttons */ .buttons { text-align: center; 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); color: #fff; background: #ef7d50; font-weight: bold; -webkit-appearance: none; } input[type="submit"]:hover, input[type="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-collapse: collapse; } tr, th, td { padding: 10px; margin: 0; text-align: left; } table, th { border: 1px solid #00a0b0; } th { border-left: none; border-right: none; background: #ef7d50; color: #fff; cursor: default; } tr:nth-child(odd) { background: #fff4cf; } tr:nth-child(even) { background: #fff; } tr:hover { background: #ddd; cursor: pointer; } /* Status and error boxes */ .statusMessage, .errorMessage { font-size: .8em; padding: .5em; margin: 2em 0; -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); } .statusMessage { background-color: #2b2; border: 1px solid #080; color: #fff; } .errorMessage { background-color: #f22; border: 1px solid #800; color: #fff; }
I won’t go into the details of the CSS, since this tutorial is about PHP and MySQL! Suffice to say, it styles things like the page layout, colours, fonts, forms, tables and so on.
Last, but not least, our site needs a logo. Here’s one I prepared earlier — save it in an images
folder inside your cms
folder, calling it logo.jpg
(or roll your own logo):
All done!
We’ve finished our CMS! To try it out, open a browser and point it to the base URL of your CMS (for example, http://localhost/cms/
). Click the em>Site Admin link in the footer, log in, and add some articles. Then try browsing them on the front end (click the logo to return to the homepage).
Don’t forget you can try out the demo on my server too!
In this tutorial you’ve built a basic content management system from the ground up, using PHP and MySQL. You’ve learnt about MySQL, tables, field types, PDO, object-oriented programming, templating, security, sessions, and lots more.
While this CMS is pretty basic, it has hopefully given you a starting point for building your own CMS-driven websites. Some features you might want to add include:
- Pagination on the article archive (front end) and article list (back end) so that the system can easily handle hundreds of articles
- A WYSIWYG editor for easier content editing
- An image upload facility (I’ve written a follow-up tutorial on adding an image upload feature to the CMS)
- A preview facility, so the admin can see how an article will look before publishing it
- Article categories and tags (I’ve written a follow-up tutorial on adding categories)
- Integration with Apache’s mod_rewrite to create more human-friendly permalink URLs for the articles (find out how to do this)
- A user comments system
I hope you’ve enjoyed this tutorial and found it useful. Happy coding!
I’m developing on a localhost and am getting some errors after attaching the cms to to a html site to use it as a newsletter.
These are the errors I’m getting:
Warning: session_start() [function.session-start]: Cannot send session cache limiter – headers already sent (output started at C:xampphtdocs………config.php:14) in C:xampphtdocs………..admin.php on line 4
Warning: Cannot modify header information – headers already sent by (output started at C:xampphtdocs……….config.php:14) in C:xampphtdocs……….admin.php on line 44
What would you suggest checking to troubleshooting this? Thanks, Jason
Hi Jason,
Make sure you have nothing before your opening ‘<?php’ tag in your config.php file (not even whitespace). Similarly, make sure there’s nothing after your closing ‘?>’ tag.
Cheers,
Matt
Thanks for the reply. I removed a space below the ending php tags in the config file, but it is still throwing the same error.
Are you sure it’s exactly the same error?
You shouldn’t be getting the same error if you’ve removed all characters after the ?>.
Matt
When I click on site admin this is the error displayed: Warning: session_start() [function.session-start]: Cannot send session cache limiter – headers already sent (output started at C:xampphtdocslumbercmsconfig.php:13) in C:xampphtdocslumbercmsadmin.php on line 3
but the login form still displays. When I log in these are the errors that display: Warning: session_start() [function.session-start]: Cannot send session cache limiter – headers already sent (output started at C:xampphtdocslumbercmsconfig.php:13) in C:xampphtdocslumbercmsadmin.php on line 3
Warning: Cannot modify header information – headers already sent by (output started at C:xampphtdocslumbercmsconfig.php:13) in C:xampphtdocslumbercmsadmin.php on line 43
Nothing else shows up except for the errors.
So it’s now line 13, not 14.
Your config.php must be outputting something (either that or PHP is lying!). The only thing I can think of is that you have whitespace outside your <?php … ?> tags.
If you post your config.php here then I can take a look.
These are the 13 lines in my config file (took out the user and password).
Hi Jason,
Check there’s no whitespace at the start or end of your Article.php file either.
Matt
No idea then I’m afraid!
It looks like you’re running it on Windows so you might need to make sure your files have Windows line endings rather than Mac/Unix. Other than that I can’t think of what the problem might be, if you have no whitespace outside your <?php … ?> tags.
You could remove the line:
…which will at least stop the error showing on the page. Not sure if your session will work then (it might).
Matt
Started with a fresh install and there are no errors. However sessions seem glitchy. For example after logging in I will log out and be taken to the admin homepage to add a new article, but if I click to add new article it will take me to the login form. If I click site admin without logging in I will be redirected to the admin home page again.
“Started with a fresh install and there are no errors” – A fresh install of XAMPP, or the CMS?
“However sessions seem glitchy” – Sounds like either a problem with your PHP install, or possibly your browser is caching stuff it shouldn’t.
You could maybe try adding session_write_close() just before the header() calls in admin.php – this will force PHP to write the session data to disk at that point, which may work around some problem with PHP:
http://php.net/manual/en/function.session-write-close.php
Also take a look at the session file when you’re logged in and out, and see if it contains the expected data. You can find the session folder with:
Cheers,
Matt
Hi,
I found this really useful and easy to understand so congrats.
However, when I try to click on the site admin to login I get an error message.
The error message reads:
Parse error: syntax error, unexpected T_IS_NOT_EQUAL, expecting ‘,’ or ‘)’ in C:wampwwwcmsadmin.php on line
It’s this piece of code thats giving me the problem.
if (isset( $_GET[‘action’] != “login”) && $_GET[‘action’] != “logout” && !$_SESSION[‘username’] ) {
login();
exit;
}
Can you help?
Thank you
That’s incredible training, Matt. What an awesome creation. Simple, and a fantastic learning device for designers who are new to PHP, like myself.
I wish there were 48 hours in one day and I could get by on only 4 hours of sleep.!
@cactus: Thanks! Your code should be:
@milkdoll: Thanks – the tutorial was quite a big project! I’m happy that people are finding it useful. 🙂
Tried deploying this source code in PHP 5.3.5 and WAMP 2.0 getting errors.
If i take cautious evaluation with isset($_GET[‘action’]), then errors are gone, but if i attempt to add new article, it redirects to login page and am unable to proceed further,
Could you please check this and comment..
phpuser is having pretty much the same problem as me.
I started off with the code that you originally said and found it gave the error undefined index action on line 6 (twice) and line 11 when I clicked on the log in button.
When I added in isset it gave me the previous error.
I tried your code which I assume was the same as in the tutorial and still get the undefined index error.
Any ideas?
@phpuser & @cactus: That’s probably because you have error_reporting set to E_ALL in your php.ini. The default is (E_ALL ^ E_NOTICE).
A workaround is to exclude notices from your error reporting – add this to the top of your admin.php:
I’ll update the code to check that the action and username values are set, to avoid this issue.
@cactus: You got that other error because your code had a syntax error in it.
Cheers,
Matt
Article and code now updated. You can grab the latest code here:
http://www.elated.com/res/File/articles/development/php/cms-in-an-afternoon-php-mysql.zip
Thats solved it thanks a lot!!! 🙂
@cactus: Great stuff 🙂
Hey Matt…thanks a ton for this tutorial.
I have a question…everything works great except one thing for me.
For some reason, the date is incorrect on the index page. I changed the date to be:
date_default_timezone_set( “America/Los_Angeles” );
Which I found on this url: http://www.php.net/manual/en/timezones.php
I’m not quite sure where I’m going wrong.
Any suggestions?
Thanks!
Chris
Hi Chris,
How is the date incorrect? Is it a few hours out?
Did you change the timezone after creating some articles? If so then the articles would have been saved using the old timezone but their dates are being read using the new timezone, which might explain the difference.
Hey Matt,
Thanks for getting back to me so quickly!
The date currently shows 31 December 1969 for every post whether it’s in the article archive or on the homepage.
I don’t know where I’m going wrong. I checked to make sure in phpmyadmin that it’s set to DATE like it should be and it is.
:/
Chris
– Amendment –
Actually…it looks like it shows “31 December” for the home page posts of articles and then on the article itself it says “PUBLISHED ON 31 DECEMBER 1969”
Then on the Article Archive it shows “31 December 1969” for every article (even if I post a new one now, it will still say that same date).
[Edited by christopherjc on 22-Mar-11 18:32]
Chris,
“31 December 1969” implies that the date is being passed from or to MySQL as zero or null (1 Jan 1970 is zero, minus a few hours to allow for your timezone difference).
I don’t think this is a problem with timezones. It’s a problem with the dates not being properly exchanged between PHP and MySQL.
The next step would be to look at your MySQL table using the mysql tool or phpMyAdmin to see if the dates are in the article records or not.
If you need any further help with your problem, please start a new topic:
http://www.elated.com/forums/authoring-and-programming/topic/new/
Cheers,
Matt
Hi matt,
Sorry to be a bit late…Thanks for the new code its working fine…
Great script, one of the most useful things I could ever imagine to use outside of a forum source.
So as return I came here clicked ads on purpose, and was just wondering if you thought of developing a comment page to go with, as in after the user views the article he or she could comment on it.
I am currently in this very progress only on localhost though, but thanks for the source and your time sir, keep up the good work and God bless.
@phpuser: Great stuff 🙂
@DuckNorris: Not a bad plan – maybe I’ll write a follow-up article showing how to add comments. Thanks for the suggestion.
In all honesty I hate WordPress, and cannot stand how popular it is same reason I do not own a .com domain.
(Just everything is so mainstream) [I rather stick out]
I just find if there was a basic underground script that could function as well as the giant WordPress and even got more ideas for just this script…
User comments… They don’t have to register or anything just have there a name field if not field name person, Anonymous hidden field for date input and their message, strip html tags, and add a very simple math function to avoid spam, cause robots can’t do math… lol
Add a simple poll script for the users to only see on the main page, no log in required to vote, but not have their be a set cookie once on the url’s homepage
(Optional) Registration This allows user(s) to suggest polls always be logged in and change the theme
These and more ideas are ‘a float’ in my mind, and I could really be developing them myself however I shared with you since you shared with me first, and for that I again have to say thanks.
–Daniel
@Daniel: Thanks for your additional ideas. They’d all make interesting tutorials, so I’ll add them to the list of possible future topics!
great script, and great tutorial 🙂
i just wan’t to ask how to use this, if we wanna more tabs(with other type of news(sport, business,cars…)). i tried, and it shows me error
Fatal error: Class ‘Vozac’ not found in C:xampphtdocscmstakmicari.php on line 40
if you can help me, i would be really grateful 🙂
@adiomb: It sounds like you forgot to include your Vozac (Article?) class file at the top of your script.
If you need more help with creating multiple tabs (categories?) then please post your questions in a new topic:
http://www.elated.com/forums/authoring-and-programming/topic/new/
Cheers,
Matt
i fix this problem, now it s ok, thank you 🙂
but i have another problem, when i want to add new post, it says it is successfully added but it doesn’t aper in db nor on page.
@adiomb: Have a look in your PHP error log. You might find some clue there.
If you need any further help with your CMS please post in a new topic:
http://www.elated.com/forums/authoring-and-programming/topic/new/
Thanks,
Matt
i have problems with characters Ä,ć,Ä‘,Å¡, somewhere they, somewhere they don’t, i remove htmlspecialchars filter from entire code, and they won’t to appear, again. in db in thepalcecharacters, there are question-mark “?” and characters like this “Å¡
other question is how can i make in news to appear month on my language. Instead of January to appear Januar, and so on…
@adiomb: Sounds like you have a Unicode/UTF-8 issue. Put this meta element in your page’s head section:
Also, make sure your MySQL table and connection use utf8:
http://www.bluetwanger.de/blog/2006/11/20/mysql-and-utf-8-no-more-question-marks/
Cheers,
Matt
Absolutely great tutorial. Works a dream on my local set-up, thanks!
Would you be able to explain what would be required to upload images to the database?
That would be really really useful!
@m4xjb: Thanks – glad you enjoyed it. 🙂
To do image uploads, in a nutshell:
– Add enctype=”multipart/form-data” to your form tag.
– Add an <input type=”file”> field to your form.
– Use the PHP $_FILES array to retrieve information about your uploaded image(s), and process it/them: http://www.php.net/manual/en/features.file-upload.post-method.php
Hope that helps! Let us know if you’d like more info.
Thanks matt! Found it a bit tricky extrapolating the php.net page to this example. I’m getting there but not quite… Here is progress so far:
I’ve added the input and label to the form in editArticle.php
In Article.php I have:
1) Added the property $image in the article class.
2) Created and populated an image object in __construct() with:
3) Added the image to the article table by adding this to insert() and update():
4) And finally added the image to viewArticle.php:
Have I covered everything? Albeit incorrectly!
I’m sure I’m creating the image object in __construct() wrong.
Also, I’m confused with adding the image to the article table with insert() and update(). As the image not a string or an integer, what alternative do I use for PDO::PARAM_???
Atm I’m getting an ‘Undefined index’ error message in the browser.
Any help is really appreciated. Can’t wait to adjust the code to my own needs once it’s all up and running 🙂
Cheers!
What you’ve done certainly looks correct off the top of my head. But you’ll also need to use the PHP move_uploaded_file() function to move the uploaded file from the temp folder to a folder within your website (eg “/images”). Then your markup would be:
It’s also wise to use is_uploaded_file() to check that the file was actually uploaded by the user (for security reasons).
http://www.php.net/manual/en/function.move-uploaded-file.php
http://www.php.net/manual/en/function.is-uploaded-file.php
“I’m sure I’m creating the image object in __construct() wrong.
Also, I’m confused with adding the image to the article table with insert() and update(). As the image not a string or an integer, what alternative do I use for PDO::PARAM_???”
You shouldn’t add the image to the database! It’s possible (using BLOBs), but it’s much easier and more efficient to store the image file in a folder on your website, and just store the image’s filename in the DB (which I think is what your code will do, although I haven’t checked it). The image filename is of course a string.
Cheers,
Matt
[Edited by matt on 18-Apr-11 06:37]
Thanks matt,
Ok, so using $_FILES in __construct() is correct? I thought I maybe should have used $data like the rest of the objects.
Then I should use PDO::PARAM_STR in the insert() and update() functions to store the image filename in the database… In that case I need an image field in tables.sql. So for this I used data type: varchar(255) NOT NULL. Does that seem ok?
And after that line – still within insert() and/or update() – I add the move_uploaded_file() function like so:
Where ‘image’ is the name of the <input>. But I’m getting an error saying that the ‘image’ is undefined 🙁
Again, any help is much appreciated! I’m hoping that others will benefit from this too 😉
@m4xjb: $_FILES[‘image’] contains all the info about the uploaded image (assuming your file upload field is called “image”). I’m not sure what $data[‘image’] holds without seeing all of your script. It might help if you called your property something like $imageFilename instead of $image, to avoid confusing it with the “image” file upload field and $_FILES[‘image’] element. You can populate $imageFilename from $_FILES[‘image’][‘name’].
varchar(255) should be fine for storing the image filename.
‘image’ is undefined implies that the user didn’t upload an image when they submitted the form. (Presumably it’s an optional field?) You need to check that $_FILES[‘image’] exists before you try to access any of its elements, call move_uploaded file(), etc:
Also, note that $target_path needs to be the full path to the images folder (from the volume root). eg /home/username/website/htdocs/images.
Hi matt
this is just a great script
but i got error
i just installed the script on wamp
but when i open i got this error
Fatal error: Uncaught exception ‘PDOException’ with message ‘SQLSTATE[28000] [1045] Access denied for user ‘usman’@’localhost’ (using password: YES)’ in C:wampwwwclassesArticle.php on line 103
PDOException: SQLSTATE[28000] [1045] Access denied for user ‘usman’@’localhost’ (using password: YES) in C:wampwwwclassesArticle.php on line 103
Can u plz tell what this error
plzzzzz solve my problem plz
Thanx,Usman
Hi Usman,
That error means that your PHP script couldn’t access your MySQL database using the username/password that you put in your script.
Make sure the username, password, and database name in the script exactly match those in your MySQL database. Also make sure that you have created the MySQL user and password correctly, and given the user permission to read and modify your articles table.
I did understand that
can u tell what to write in these places
DB_DSN”, /// Here I have to write “localhost”
dbname //// Here My Database Name
DB_USERNAME///// What To Write Here
DB_PASSWORD //////What To Wirte Here
plzzzzz help
username: “root”
password: “”
hi, it is me again 🙂
i created few more tabs, working on the same structure, everything works except archive and viewVozac… when i click on specific news it returns me to the homepage(index) and in navigation bar it writes
http://localhost/cms/?action=archiveVideo?http://localhost/cms/action=viewVozac&vozacId=50
but doesn’t show archive or article(vozac in this example) i checked everything many times, but i can’t find where i making mistake
thanks in advance
@usman ikram: Yes, you need to put your MySQL database name, database username, and database password in those constants.
@adiomb: Please post your whole index.php script in a new topic so we can take a proper look:
http://www.elated.com/forums/authoring-and-programming/topic/new/
Matt
Help! I can’t get past the first part!
I created the database and the schema, but when I try to add the Schema into mysql I get this error message:
“ERROR 064 (42000) at line 2: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ‘(id))’ at line 9.”
I have no idea what I’m doing wrong as I’ve literally directly copied and pasted the code that was given.
Can anyone advise?
Oops! A comma was missing in the table schema in the article. (The code download is correct.)
should be:
I’ve fixed up the article now. Let me know if you encounter any further problems.
Thanks!
Matt
First, thank for make a good tutorial for the beginner.You did great thing.
So this is the point.
1.Pagination
I can retrieve the data from database and pagination the data .
But i did the whole thing in one file but i don’t know how to embed my code in your schema.
2.Categories
Here is the some problem. I got a umlimited subcategories class and it work very well. When i want to expand the functionality of your schema, the same problem came again. I have no idea how to do.
3.Maybe i just don’t understand your schema that further and i am a new guy.
What i know is :
user->action->script function->class function
->script function ->templates ->user
like mvc ?
End: give me some advices as soon as possible.
Thank very much.
nice tutorial for beginner like me , it is realy helpful but please i would like to paginate my articles.how is this possible and please can u send me the codes for doing this? thanks a lot.
@olubee: The basic idea behind pagination is:
1) Use the MySQL LIMIT clause to return just the articles for the current page: http://dev.mysql.com/doc/refman/5.0/en/select.html
2) Use SQL_CALC_FOUND_ROWS and FOUND_ROWS() to retrieve the total number of articles in the table
3) Use the above information to calculate the start row positions for each page
4) Display the article list, along with links to other pages
I am download this cms and run on local but I have this error when go to index.php
please help me, I am using Easyphp on my local
@alisoftware: See http://www.easyphp.org/forums/9/145328/php_and_mysql_-
Or use XAMPP instead:
http://www.apachefriends.org/en/xampp.html
are you sure solve my problem with XAMPP?
Because I have same problem with other cms and do not have problem with other else such as Datalife Engine or other Popular cms
And I have a request (maybe question!!), how can I add comments section to this cms?
[Edited by alisoftware on 24-May-11 04:27]
hello, i’m having a problem with it escaping the code
i type in the correct link code or img code and it comes out like
<a href=”http://website.com”>hi</a>
could you please tell me how to fix this?
using apache2/mysql/php5 on linux
thank you,
@jasonh_000: You mean the slashes? Looks like you have magic quotes enabled – turn the feature off:
http://php.net/manual/en/security.magicquotes.php
thanks, even though in my only php.ini and my other .ini and .conf files i had this turned off, it was still using it.
so i toggeled it off via .htaccess
thanks for the script and for the reply to my issue.
Hi Matt,
This is a great tutorial so thanks for sharing your knowledge!
I noticed something interesting after I updated my Browsers – the Save Changes button no longer works when saving a NEW article…all other buttons work, and you can edit and re-save an existing article fine, but when adding a new article the Save Changes button does nothing – you keep clicking it and the article doesn’t save.
This is the case in Mozilla 4, and Google Chrome 12.0.742.91 but was fine in all previous versions.
It still works OK in Internet Explorer 9 though.
Just something odd I thought I would bring to your attention, if you have any thoughts!
Thanks again,
Chris
i have problem with picture upload when editing article, when adding new article, it works
this is code from class Article:
and code from admin.php
@ChrisJ: No problem! I can’t reproduce your bug though. Just tested using Chrome 12.0.742.100 and Firefox 4.0.1 (Mac) and I could save new articles every time.
Maybe there’s something about your setup that’s causing the problem? Have you tried looking in your browser error consoles?
Cheers,
Matt
Hi,
I’m still learning PHP. This tutorial is of great help for me. The only problem is: in German we have umlauts like ä ö ü ß and Ä Ö Ü. This CMS swallows all umlauts, in text and in title. How to keep the umlauts?
The solution is:
1. ensure that your web server is sending the correct content-type header:
Content-Type: text/html; charset=utf-8
(you can send this header also at the beginning of a php script)
2. change the preg_replace command in Article.php to:
preg_replace ( “/[^.,-_'”@?!:$ a-zA-Z0-9äöüßÄÖÜ()]/”, “”, $data[‘title’] );
E na Língua Portuguesa como seria o código? Como temos palavras acentuadas e com “ç”, fiz um teste utilizando o código acima para o alemão, não funcionou em português. Deu erro, não saiu nada.
Do jeito que está, só para exemplificar, a palavra “código” é exibida assim: “cdigo”; “é”, “à”, por sua vez, nem aparecem no texto.
@Gerhard: Thanks for your solution. I forgot to allow for accented characters in the regular expression. Good catch! 🙂 I expect a more flexible regular expression is needed here…
hey how is it going, let me first start of by saying thank you i was searching for atleast 12 hours trying to find one of these and finally found a great one! the only problem is, how can you add like embed youtube videos in the content secion, so if its a tutorial or something, also if you could just give me a little help for some reason wen ever i add 2 posts it goes out of order. please get back as soon as its a good time for you.
thanks
@envizionx: Just find your video on YouTube, click Share, click Embed, and copy/paste the iframe markup into your content field.
The posts are in reverse date order (newest first). You can change this in the Article class’s getList() method.
Great tutorial, I’ve got it started and am already modifying it for my purposes with no problems!
Now I’m thinking of how to make the installation more secure in addition to the security tips you already posted. What do you think of securing config.php using .htaccess as shown with the code below?
@ANA Designs: That should work, provided your Apache server is set up correctly. Give it a go!
To be even safer, move your config.php outside the document root.
Could someone tell me how much of this I would have to change if I were to do the tutorial on a Windows machine?
Thanks.
Awesome tut – huge thanks, Matt.
Cheers,
Phil.
@Chett: Hardly anything, I’d have thought.
@bionic frog: You’re welcome – glad you liked it!
Thank you SO MUCH, Sir Doyle!
This is one of the most clearly explained, concise tutorials I’ve ever read. I’m working on a php site, and I’m new to php in general and very new to OOP. I wish I’d found this tutorial ages ago when I first started learning php and working with WordPress. This tutorial should be recommended to anyone who wants to work with WordPress or any php-based CMS, as it is a simplified example of how such a system works. The site I’m currently developing is simple and from scratch, and this article has helped bridged the gap between what I’m now trying to do and what I’ve seen done in complex CMSs.
Again, many, many thanks. You have made my life a bit easier.
– Emily
Hi All,
Just to let you guys know – I was that impressed with this tutorial, I invested in Matt’s book “Beginning PHP 5.3”.
It is excellent – definitely worth the money. If you’re new(ish) to PHP like I am, the book is worth it’s weight in gold.
Everything is explained in simple to understand terms and the books covers the right amount of subjects for anyone starting out in PHP coding.
Well done Matt on a great book – many thanks 🙂
bionic frog
P.S. Matt hasn’t paid me for this post… 😀
@esommer: Thanks for your kind words. 🙂 Yes, most CMS work in the same basic way, even if they (usually!) have lots of extra features. I’m glad my tutorial helped explain the concepts.
@bionic frog: Thanks so much for buying my PHP book and recommending it – I really appreciate it. 🙂
When I post an exterior link in the content of an article, it wraps the domain with and slaps the local domain on the links as well.
So when I link to a href=”http://www.external.com” it turns it into a href=”http://www.cms.com/”http://www.external.com”
I tried disabling magic quotes by creating an .htaccess file and putting:
php_flag magic_quotes_gpc Off
in the file, but the site then produces an internal server error. Any suggestions? I’m using a third-party server.
Thanks!
Hi Matt.
I’m developing a CMS that in short I wiil upload to a hoster.
Following your detailed CMS, congratulations, I’ve added some changes. The most important is that users may, and that’s the point, write their articles, so I created an user form for them to do so, althought they can’t change or delete the already stocked in DB.
The purpose of the site is to compile the history of a proffesional group that is almost 60 years old, narrated by it’s members, so I expect many entries over the next year.
Now my request.
First, I soon will need to paginate by years, from 1952 y 2012.
I saw in your “Build a CMS in an Afternoon…” forum your response to a member, but it´s not so easy for me to implement.
Seccond, I’d like to secure the site a little bit more.
Could you help?
So many thanks.
@Sparkus: Works fine for me on my dev server, so I’m assuming it’s something strange about your server setup. Maybe there’s a security script running that is attempting to sanitize all URLs or something?
Also you can check if magic quotes is actually off at runtime using http://php.net/manual/en/function.get-magic-quotes-gpc.php .
@mar: I can’t go into detail about pagination here. I might write a follow-up article on pagination and other topics however.
Not sure what you mean about “securing the site”. If you have specific questions on securing websites, please post a new topic here:
http://www.elated.com/forums/authoring-and-programming/topic/new/
@Matt: Thanks for the reply. Perhaps it is because I have the cms currently installed in a subfolder of a directory that is a root for a WordPress install. I used the cms with an addon domain. Is that known to cause problems?
Should I host them on separate hosting accounts? Perhaps I should put them both in a separate subdirectory and point to each using an addon domain so one is not under the other.
OK matt. Thanks.
While expecting for your follow-up article, I’ll try to find some info in the www. Same for security.
Thanks again.
@Sparkus: No idea I’m afraid. I’d start by creating a separate website if possible (perhaps locally) and installing an identical copy of CMS code there, just to rule out problems with the code. If it works OK then start digging into your server/PHP config a bit more.
Did you run get_magic_quotes_gpc() to see if magic quotes is on at runtime or not?
Hi Matt, I just wanted to say that I would also appreciate if you did a piece on pagination for this cms. I’m new to php but I can get it to work on stand-alone scripts if you know what I mean.
thank you….
That was a splendiferous tutorial and works very well. I was just wondering, I’ve integrated the AJAX Comments System from http://tutorialzine.com/2010/06/simple-ajax-commenting-system/ but it’s set up so that I’m accessing the Comments table directly from the viewArticle.php page. Does that kind of defeat the entire purpose of the schema or does it really matter too much?
@Matt: Finally got around to running the magic quotes test and it returned a 1, which means they are on.
Guess I’ll have to contact my server host to turn them off or apply a workaround to the CMS code.
@DOC: I don’t understand the question I’m afraid. Also I’m not familiar with that comments system. However if it works and it’s not causing any problems then I’d leave it as it is!
@Sparkus: Just run stripslashes() on the posted content from within Article:storeFormValues(). For example (not tested!):
I downloaded your code and followed the tutorial but I must be missing something. the cms folder is in my htdocs folder.
I then create the database cms in XAMPP then what’s the next step? I’m a little stuck as after doing this I try and open the php files and I see this. Is there something else I need to do?
title . ” | Widget News”; require( TEMPLATE_PATH . “/viewArticle.php” ); } function homepage() { $results = array(); $data = Article::getList( HOMEPAGE_NUM_ARTICLES ); $results[‘articles’] = $data[‘results’]; $results[‘totalRows’] = $data[‘totalRows’]; $results[‘pageTitle’] = “Widget News”; require( TEMPLATE_PATH . “/homepage.php” ); } ?>
Is it permissions or something, hope I don’t sound like an idiot as this is helping my basic understanding of php and mysql greatly.
What a noob I didn’t add the username and password to the database! Keep up the good work Matt!
@Matt8: Glad you got it working 🙂
Hey Matt
What’s the best way to add an image upload facility to this, do you have any links?, I’ve searched online but can’t find anything useful.
Also what’s the easiest way to have multiple pages which can be edited? Would I recopy the entire code and the files and folders and just rename homepage in php code to something else like “newpage”.
@Matt8: Check out http://www.php.net/manual/en/features.file-upload.post-method.php for info on adding a file upload feature using PHP. It’s fairly straightforward. Exactly how you do it depends on how you want the CMS to work. One common way is to have a separate image upload feature that uploads the image to an images folder, then the user adds an img tag within the article, referencing the uploaded image URL. Rich text editors such as http://ckeditor.com/ and http://www.tinymce.com/ can make the process easier / smoother.
Not sure I understand your second question. You can already create and edit multiple articles using the CMS in the tutorial.
Cheers,
Matt
hi friends,
any one can help me to create a cms using these coding for the following template please….??
http://1solutionmy.com/cms/
regards..
I downloaded and follow this code to create a cms. its working fine.. very simple and smooth coding and design..
But I could not use use with another cms template…
[Edited by riffaz on 15-Nov-11 23:39]
Hi,
Great job.
I without any knowledge in CMS , MySql and PHP, i manage to follow your tutorial. Indeed a great article.
But i have same problem:
http://localhost/cms2/index.php – work fine
but when i click on the article its shows the root directory
http://localhost/cms2/?action=viewArticle&articleId=1
it suppose to be
http://localhost/cms2/index.php?action=viewArticle&articleId=1
how to correct this.
I change nothing at your codes.
Thanks
Hi,
Great article, I have followed everything to the letter, but for some reason when I go to my url I get the following error…
Fatal error: Class ‘PDO’ not found in apache2htdocsclassesArticle.php on line 103
Does anyone have any idea what ive done wrong?
Thanks!
@matt2002 I’m no guru but maybe it has to do with enabling PDO in your php.ini file….you may have done some fussing around with this file already. Try adding these lines to the file:
extension=pdo.so
extension=pdo_sqlite.so
extension=sqlite.so
extension=pdo_mysql.so
Someone tell me if I’m steering this guy in the complete wrong direction.
@DOC Thanks for the suggestion, I just tried that and also
extension=pdo.dll
extension=pdo_sqlite.dll
extension=sqlite.dll
extension=pdo_mysql.dll
as I’m running on windows, but still getting 403, want this to work so bad!!!
http://localhost/cms2/?action=viewArticle&articleId=1
this cause an error when reading the article.
If i manually type this
http://localhost/cms2/index.php?action=viewArticle&articleId=1
its works fine.
What is the problem?
Why the link generated is wrong?
How to rectify this?
Hi,
This was a great article and it really helped me, but I am current having two issues.
One of which is on the homepage.php it is not showing any articles, even though I have entered some into the database and I can’t seem to find any errors.
Second I am receiving this error:
“Forbidden
You don’t have permission to access /cms/templates/ on this server.
Additionally, a 404 Not Found error was encountered while trying to use an ErrorDocument to handle the request.”
When I am trying to access the link on the home page to the article archive.
Thanks.
Hi,
I managed to resolve my previous issue by re-installing php. However I am now trying to create a line in the header which will use the article ID to create a menu along the top, however I have tried this…
but it doesn’t work on all pages only the homepage.php, when I drill down into an article the menu doesn’t show and i get the following error
Notice: Undefined index: articles in apache2htdocstemplatesincludeheader.php on line 12
Warning: Invalid argument supplied for foreach() in apache2htdocstemplatesincludeheader.php on line 12
– any ideas?
@ramkumar: http://localhost/cms2/?action=viewArticle&articleId=1 should work if your web server is correctly configured to recognize index.php as an index file.
If you want, you can change ‘.’ to ‘index.php’ in all the page templates, eg:
to:
Or for more flexibility, create a constant in config.php holding the index page URL (e.g. ‘.’ or ‘index.php’), then change the templates to use this constant throughout the CMS.
@matt2002: To do that you’ll need to include the lines of code in viewArticle() in index.php to retrieve all the articles, like in the archive() and homepage() functions:
I must admit, all those errors are due to web server error (index.php was not included). Thanks alot. Problem solved.
@cjcarey: You shouldn’t be trying to access /cms/templates/ in your browser.
Are the articles in your database?
Awesome. Thanks for explaining the code step by step. I’m totally new to PHP/Basically everything so it really helped me out understanding what each step was actually doing. I have a question (possibly stupid). It is possible to have the CMS displayed to the user in a website I already created? Like inside a specific div on a page instead of having its own page?
Nevermind I figured it out. Thanks again for this. Really well done.
Hi,
Thank you for the tutorial.
but I have problem when I click on the article archive it shows http://www.gtmi.co.uk/cms/?action=archive and when I view articles it shows http://www.gtmi.co.uk/cms/?action=viewArticle&articleId=2
how can I correct this. Any help appriciated.
@QWCW11: Glad you got it working!
@ket_mit: See my answer to @ramkumar above.
Hey I’m wondering if anyone here would know how to apply a mod_rewrite to get a pretier url for each article. What I tried was
…but I’m new and clueless with this Apache stuff so I’m not surprised it doesn’t work.
@DOC: Looks pretty close. Try this:
Great Thanks for the Great Work Done Here, Very Very Nice Article With Great references and resources
Kudos for a great tutorial!! I have learned a lot from it and continue to learn.
My trouble is I am using it to take notes on my web site development lessons. When I try to add html code to contents it doesn’t show up in the viewed article but when I look at what is stored in on my server it is there.
What can I do to display my notes for example :
<html> is the tag at the top of the code.
Thanks for the help.
[Edited by digiguy on 28-Nov-11 20:01]
Thanks very much for your tutorial which I’ve just got working, next step is to tailor it to my own needs.
Just a couple of points…
Might be worth mentioning that when adding an article, the Publication Date has to be in the following format YYYY-MM-DD, it took me a few goes before working this out.
Secondly, has anyone sorted out the use of hash() to mask passowords. I’ve gone to the link provided but can’t quite make sense of it.
Thanks
Rog
@digiguy: The CMS is designed to output the HTML exactly as you enter it. So if you enter eg <p> then the CMS will display <p> in the article page, which the browser renders as a paragraph.
I get round this by HTML-encoding all angle brackets in my article content as I enter it. So <p> would become <p>. It’s a bit of a pain, but you can easily do a search-and-replace in a text editor then paste the result into the CMS.
There are other ways round it too, like using CDATA.
Or you could make the CMS HTML-encode the article content when displaying it, using http://php.net/manual/en/function.htmlentities.php . But then you wouldn’t be able to create actual rendered HTML elements (p, span, div, ul/li etc) in your content, since all your tags would be HTML-encoded automatically.
@wolfenr:
1. It does this already using an HTML5 placeholder (though you need to have a browser that supports placeholders).
2. hash() generates a unique one-way hash string based on the supplied plaint-text string (a password in this case). This hash is always the same for any given string. So you first hash the password you want to use, and the store the resulting hash string in a variable in config.php (eg $hashedAdminPassword). Then when the admin attempts to log in, you pass their supplied password through hash(). If the resulting string matches $hashedAdminPassword then you know they entered the correct password.
It is impossible (or at least very, very, very hard) to work out the original plain-text password from the hash. So it’s a fairly secure way to store a password in a config file.
Cheers,
Matt
Matt, your a genius… okay maybe just a bloody good programmer.
I see what you are saying. Truthfully I had to try out the “htmlentities” and as I said, I see what your saying. I will try out your solution as that does make a lot of sense.
Don’t know what CDATA is so I can’t look into that.
All in all this is meant to be a learning tool and you have done it. I am learning!
Thanks a bunch!
I have everything up and running, and have even restyled everything to fit in to my current site, however, when I save an article, anywhere quotations are use, I get something that looks like the following.
“front motor plate\\\’s thickness. ” For example.
Everytime I edit the article, more are added. It automatically breaks any link or IMG tag as well. I’m sure this is a document encoding issue, but I would appreciate any help I can get, I am still getting my feet wet in PHP and MySQL.
Thanks!
@Brian Esser If I understand you question correctly, Matt answered it earlier. He said to add
in the Article class file (just the second line to the storeFormValues() method). I had a similar problem and that solved it.
[Edited by DOC on 02-Dec-11 17:34]
Thanks! I missed that earlier, worked like a charm!
Now to figure out categories…
@digiguy: No problem 🙂
@matt
So I figured out the problem with the 403 error (I messed up a few links), but I am still having a difficult time figuring out why my articles are not appearing in the homepage or archive. I checked my MySQL database and everything seems to be in there and they also appear in the listArticles page.
Thanks for any help!
@cjcarey: What are the URLs of the homepage and archive page, so I can take a look?
Actually I finally figured it out, I had been directing to the wrong page. It was a very obvious mistake that took way too long to figure out.
Thanks for the help everything is up and running now.
@cjcarey: No problem – glad you got it working 🙂
Hi, I followed your article this morning, and really enjoyed it. Everything was so well explained.
But I am having a problem now that I have finished it 🙁
Fatal error: Call to undefined function: date_default_timezone_set() in /usr/local/pem/vhosts/101568/webspace/httpdocs/CMS/config.php on line 3
I copied your code, but thats the error I get. In that line I have :
date_default_timezone_set( “Australia/Sydney” ); // http://www.php.net/manual/en/timezones.php
I have checked it off the phpmanual site and I have entered it correctly, but I get the error.
Thanks in advance for your help!
Also, I just commented out the date_default.. line in the config file, but then I get the following error:
Parse error: syntax error, unexpected T_STRING, expecting T_OLD_FUNCTION or T_FUNCTION or T_VAR or ‘}’ in /usr/local/pem/vhosts/101568/webspace/httpdocs/CMS/classes/Article.php on line 15
Is it related? Or have I made a mistake somewhere else as well?
[Edited by MisssRAE on 17-Dec-11 17:47]
Hi, I figured it out. After some digging I discovered that both PHP4 and PHP5 for were enabled, and PHP4 was set to the default. But when you look at the initial summary page it says it is running PHP5. Thanks if anyone looked into this for me.
@MisssRAE: I was going to say that it’s probably because you’re running PHP4!
Hi there!
Great tutorial! I’m trying to learn the basics on php. Understood everything, but i think there is something missing! Text-areas on the backoffice don’t allow html :/ how to add this component?
Tried to use some wysiwyg php scripts but none worked well!
If you can give me an hint, i would appreciate!
Can anyone point me in the direction of adding images to this?
I have just followed your marvelous tutorial and have got it working on my localhost mysql. Thank you so much for a beautifully concise and clear explanation of what is involved.
I would like to be able to schedule when my articles appear on the homepage.php and have them not appear there after a certain date (but remain in listArticles, archives.php and viewArticle.php).
I believe I need to add two more fields to the cms articles table: pubstart and pubend, which I should then get from the mysql cms database and use in the homepage.php to publish and unpublish the title in the homepage.php. Am I on the right track?
But I am not sure how to code this. Could you or any of the other forum participants advise me on how to do this?
Many thanks,
Shelley
[Edited by shelley3 on 28-Dec-11 14:01]
Hi,
Very nice tutorial matt. I’m trying to learn php. I thing about pagination the articles but for my is not so simple. Maybe helps of course if you have a moment time. Many thanks.
Great tutorial, just quickly browsed through and this is exactly what I am looking for; a simple CMS without any unnecessary clutter that is easy to style, etc.
I’m pretty new to PHP which is why I intend to follow every step in this tutorial to help me learn. Is there a way to post to separate pages from the backend without creating a separate CMS for each one? For example, on my webpage I would like to create a news page and then a separate page for gig dates, it would be more convenient to then be able to select which page to publish to, as opposed to having to login to separate backend pages.
How difficult would it be to do this? and could somebody point me in the right direction.
Thanks,
Adam
@Colucas: If by “don’t allow html” you mean that the CMS sends HTML straight to the browser instead of HTML-encoding it, see:
http://www.elated.com/forums/topic/5114/#post21828
@odinsmasher: See http://www.elated.com/forums/topic/5114/#post20643
@shelley3: I can’t code it for you, but yes, you are on exactly the right track! Create pubstart and pubend fields in the DB, and corresponding pubstart/pubend properties in the Article class, then modify the methods in the Article class to read/write these values from/to the DB. Then you can compare the 2 properties of the Article object against the value of time() to determine whether to display the article or not.
Thank you so much for your reply, Matt.
You have confirmed what I partially managed to figure out: i.e. that after adding the pubstart and pubend fields in the DB, their properties should be defined in the Article class. I am in the process of coding the methods to be able to time the display of an article. Not there yet, but I will post my results when I get it right (or whine and cry if I can’t). 🙂
The role of defining a class (which I had not done before in php) became much clearer after pondering all this. I am really getting a good understanding of php/form/html pages/database interaction from examining all the files from your cms tutorial.
What a powerful package!
Many thanks again!
Shelley
@AdamBarry: Yes. Essentially, you’d just create an article “category” database field and corresponding property, and modify the article edit form to allow you to assign a category to the article (eg “news” or “gigs”).
You’d also modify Article::getList() to allow you to pass in a category to filter by.
Then you could modify archive() in index.php to look for a “category” variable in the $_GET array, and pass the category inside the call to getList() to bring back just the articles in that category (news or gigs). archive() could then require either a news.php or gigs.php template, instead of archive.php.
You’d then view your news and gigs listing pages with:
/?action=archive&category=news
/?action=archive&category=gigs
Cheers,
Matt
@shelley3: You’re welcome – I’m pleased you learned a lot from the tutorial. 🙂
How i can use UTF-8, for save & load news in mySQL?
:-/
@GLinBoy
just add
after new PDO line.
ex.
[Edited by chotikarn on 12-Jan-12 22:28]
@chotikarn
thank you.
but i have a problem; I can find “$conn = new PDO( DB_DSN, DB_USERNAME, DB_PASSWORD );” in article class an replace with “$conn = new PDO( DB_DSN, DB_USERNAME, DB_PASSWORD, array (PDO::MYSQL_ATTR_INIT_COMMAND => “SET NAMES utf8″) );” but i got this error: Fatal error: Undefined class constant ‘MYSQL_ATTR_INIT_COMMAND’ in C:wampwwwclassesArticle.php on line 103
😕
I don’t know that what happened!
something that i forget it is that i using WAMP 2.0 & PHP 5.3.0 & MySQL 5.1.36 run on windows 7 ultimate.
[Edited by GLinBoy on 13-Jan-12 02:09]
@GLinBoy
i use XAMPP 1.7.7 on Windows XP SP3 and it’s work fine on me (i use thai language).
but,it has many way to use utf-8, i hope this one might work on you.
or else try normal way of “mysql_connect” instead of PDO.
if you need more information about PDO just visit php.net
PS.sorry for my bad english.
[Edited by chotikarn on 13-Jan-12 09:16]
Really great tutorial Matt! Congrats!
I’ve set my database and installed it, and went on the admin site on my webpage, wrote an article, but it didn’t appear anywhere…
It says “0 written articles”
Did I miss something? 🙂
Hello Janjetina,
Have you named the fields in your database exactly the same as the fields specified in the Article.php, editArticle.php and other php documents?
(The names in this tutorial are “id, publicationDate, title, summary, content” and are case sensitive.)
Have you specified the field types in your database? Have you made “id” an auto-increment and the database index?
Have you specified the path to your DB_DSN in the config.php? (e.g. “mysql:host=localhost;dbname=your_db_name”)
Is the timezone in the config.php set to your local time?
Are you getting any error messages like “failure to open . . . ” , etc?
🙂
Shelley
Thank you Matt, for this tutorial! I certainly learned a lot from this and I managed to get it al working.
My next step is to try to add an image-upload, like m4xjb. I followed his steps and Matts comments and tips but I can’t get it to work.
Do I have to implement the file handle (to actually ‘get’ the file from the form and place it in the right folder) in the __construct function? Or is it done some place else (in the insert function)?
@GLinBoy: Also this might help:
http://stackoverflow.com/questions/2424343/undefined-class-constant-mysql-attr-init-command-with-pdo
@b0bx: Just call move_uploaded_file() to move the uploaded image file to your desired folder. I would call it at the point where the article edit form submission is handled (e.g. in newArticle() and editArticle() in admin.php).
Thank You shelley3!
Now it works fine, I’ve made a few changes and thus forgot about those little details.
Now what if I want to add another property in the article, for example: in between the summary and content I want another content, let’s say content2
Where and in which .php documents do I need to specify the new property and which lines of code do I need to add. (Beyond of course the ordinary label and id in editArticle.php and few lines in homepage.php) ?
Hello Janjentina,
I’m so glad this was helpful.
If you want to add more properties, you will have to add an additional field for that property into your database e.g.:
Field: content2
Type: mediumtext
Collation: utf8_swedish_ci
Null: No
Default: None
Then you will need to add that property into the cms/classes/Article.php under:
class Article
public function __construct( $data=array() )
public function insert()
public function update()
e.g. wherever
appears, add your new property
to the function (in Article.php)
For the form (in editArticle.php) you will need to add:
In each case, make sure the property name, id, $this, $data have the correct name of “content2”.
Best,
Shelley
Thanks Matt, you have been a great help.
Is there a way to tidy up the URLs to look like:
mysite.com/news
mysite.com/gigs
instead of
/?action=archive&category=news
/?action=archive&category=gigs
and also what properties would i need to add to the category field in the database table?
Thanks,
Adam
[Edited by AdamBarry on 18-Jan-12 06:51]
Hello shelley3
Thanks again for the response
However,
I get this error when writing the new article:
Notice: Undefined property: Article::$content2 in /home/users/pustolovac/klada.hr/cms/templates/admin/editArticle.php on line 30
but everything is fine on line 30. But the part I don’t understand very well is what exactly to write in Article.php in this sections:
public function __construct( $data=array() )
public function insert()
public function update()
Do I always need to put this?
if ( isset( $data[‘content2’] ) ) $this->content2 = $data[‘content2’];
Hallo @matt,
This was great tutorial i liked the way you build your code and also the explanation.
It would be very useful to add comment page, if get the time for that.
Could you please explain what should be done, if some one want to add a comment page to the cms. i can imagine the comment page would have properties like this
That is just my imagination when adding comment class to the our cms, i think the rest of the code would look like the one of the article class.
But i have got a question, should the class Comment be child class of the article some thing like
if not, how would that be programmed. It would really be appreciated if you try @matt to explain it.
Thank you very much for your contribution.
[Edited by mubuuba on 19-Jan-12 11:38]
@AdamBarry: You’ll be pleased to know that I’m writing a tutorial on adding categories to the CMS right now 🙂
Yes, you can tidy up the URLs (assuming you’re running an Apache server and have appropriate permissions) by using mod_rewrite rules inside an .htaccess file in your document root. The rules map the “tidy” URLs to the URLs needed by the CMS. For example:
@Janjetina: Did you add the $content2 property at the top of your Article.php file?
eg:
You’ll need to find all instances of the $content property in Article.php, and copy and paste the code, replacing $content with $content2 in the copied code.
eg in Article::__construct(), you’d add:
In Article::insert(), you’d make these changes:
etc…
@mubuuba: Your Comment class looks about right, but no, it shouldn’t extend Article since it shares virtually no characteristics with the Article class.
Instead, make it a stand-alone class that maps to your comments table in the DB. You can then include Comment.php inside your Article.php class, and write methods like Article::getComments() that gets all the Comment objects for a given article, which you can then display. (Or you can create methods such as Comment::getAllForArticle( $article ) if you prefer to do it that way round.)
Make sure you use at least a captcha to reduce comment spam 🙂
I’m thinking about writing another tutorial showing how to add comments to the CMS. Out of interest, would you prefer a tutorial showing how to add comments directly in the CMS itself, or a tutorial that shows how to add comments using Facebook, Disqus etc? Which do you prefer?
@matt, You are really a good programmer and you do it neatly.
MAtt as you have seen and read i am not the only one who asked that question. It is almost a hot topic here. Your cms is cool and nice that is why people like it.
I am respecting your time constraints. But matt if you could add a comment class{} in this cms would be great, because people are learning skills from there too.
I have already tried to add comment class and i did but i think i am not doing it a neat way.
This cms is great work from you respect.
But if you add that comment class and as you said categories too, it would be just a complete cms news system.
I would like that you add it to this cms..
Again Thanks a lot.
Thanks for this tutorial! I have been looking for something like this for a while.
When I login to the admin page I receive the “Invalid Username and password” error. The username and password I use matches perfectly with the ones I entered on the config.php file.
I’m stuck. What can you suggest?
Thanks.
Hello mpierce1001,
Are you using your ADMIN_USERNAME and ADMIN_PASSWORD or your DB_USERNAME and DB_PASSWORD?
Are you using PHPMyAdmin to connect to the database?
How you set your usernames and passwords in mySQL and the permissions you established (e.g. root, localhost, guest, another_username); and, if you are using PHPMyAdmin, how you configured that (in the PHPMyAdmin config.php) to communicate with MySQL determines what username and password you need to use.
I use PHPMyAdmin and have configured my username and password in the cms configure.php document to access MySQL with that name and password (not my DB_USERNAME and DB_PASSWORD).
I don’t have these documents in front of me, so I can’t explain much more than this right now. But, if you are still having a problem, I can delve into this more tomorrow.
Best,
Shelley
I am using the ADMIN_USERNAME and the ADMIN_PASSWORD to login to the admin page, but it still gives me the “invalid username and password” error. I am using myPHPadmin through Fatcow web hosting. Please help I am at a loss.
Hi mpierce1001,
Are the ADMIN_NAME and ADMIN_PASSWORD in your cms config.php file the same as the database username and password that Fatcow.com assigned to you for MySQL?
If not, change your ADMIN_NAME and ADMIN_PASSWORD to be the same as your Fatcow-assigned username and password. And make sure your cms configure.php mysql:host=the Fatcow information for the database name, and that DB_USERNAME and DB_PASSWORD match the same Fatcow-assigned username and password.
So your cms configure.php DB_ and ADMIN_ information will be the same.
My web hosting company gave me these instructions for when I begin using their MySQL server:
“Please note that your MySQL password is different from your main account password (i.e. mail, ftp, ssh) . . .”
Hope this helps.
Best,
Shelley
Still no luck. All my username and password are accurate and so is the host name url. I’m so lost…it is probably something really easy but I am so confused.
Thank you so much for your help.
Hi mpierce1001,
Have you contacted Fatcow.com support? Since you are using the phpMyAdmin through them, they should be able to tell you what is not working.
php, mysql and phpMyAdmin are very complicated to set up.
Are you on a PC or a Mac? If so, what OS?
php has a php.ini that needs to be properly configured.
phpMyAdmin has a config.inc.php that has to be properly configured.
mysql also needs to be properly configured.
So it is definitely not a simple thing. I know you are not the only one having these difficulties.
still no luck Fat Cow’s support isn’t much help. Everything is set up properly I just don’t get it.
Ok I’m pretty sure it is connecting to the database but for some reason the login function is not linking back to the data in the config.php….any ideas?
Ok I fixed the login thank you for your help!!!!
Now I am getting this error when trying to load my editArticle.php
Parse error: syntax error, unexpected ‘;’ in /hermes/web07/b2556/moo.theveganviewpointcom/editArticle.php on line 37
I believe it is in relation to the use of tinyMCE to replace the textarea form.
This is the code in my header:
<script language=”javascript” type=”text/javascript” src=”tiny_mce/tiny_mce.js”></script>
<script language=”javascript” type=”text/javascript”>
tinyMCE.init({
theme : “advanced”,
mode : “textareas”
});
This is the textareas code:
<li>
<label for=”content”>Article Content</label>
<textarea name=”content” id=”content” placeholder=”The HTML content of the article” required maxlength=”1000000″><?php echo htmlspecialchars( $results[‘articles’]->content )?></textarea>
</li>
Woohoo! Glad you fixed the login problem. How did you solve it? Knowing that will help other folks who might have the same difficulty.
Regarding:
“Parse error: syntax error, unexpected ‘;’ in /hermes/web07/b2556/moo.theveganviewpointcom/editArticle.php on line 37”
What is the code used in line 37? Looks like there is a semicolon ( ; ) that shouldn’t be where it is.
I just deleted the database and re installed it changed the code to pull from the DB username and password and bam it worked…the code on line 37 is in my previous post relating to the ‘content’ textarea. There is no ; in the code Li.e…which is why I am confused
@mpierce1001: There is a ‘;’ in your code, at the end.
Without seeing your whole editArticle.php and header.php files I can only make educated guesses, but it sounds like you haven’t delimited your PHP code properly at some point (by using ‘<?php’ to start PHP code and ‘?>’ to end it).
Thank you for best tutorial, matt. i was learn a lot from it. i was adapt it and now i have my own CMS and it work like a charm.
Thank you.
——–
@mpierce1001 your code show that you don’t have </script>. it’s might be your problem.
i have use tinyMCE before but it ruin my template(maybe i misconfig it), then i use ckeditor and it work well.
note: to use WYSIWYG editor a textareas’s attribute required must be removed.
I have installed CKEditor and it shows up. However, it swallows up everything on the page. How can I prevent that.
I still want to separate title, summary, content, and date fields so they can all be inputted separately for the database. CKEditor displays but with everything inside it’s text editor including the logged in as and logout button and the submit button….help please and thank you
For all those who want to add article categories to their CMS, I’ve just posted a new tutorial that will help you out:
http://www.elated.com/articles/add-article-categories-to-your-cms/
@chotikarn: You’re welcome 🙂
@mpierce1001: Not sure what you mean exactly. Can you post a screenshot somewhere? Sounds like you might have invalid markup, or else you need to configure CKEditor to only enhance your textarea.
@matt wow, i’m looking for it, thanks you matt. i just add my category to your CMS but this is greater than mine.
@mpierce1001 maybe you should config ckeditor for only one textarea in this case only content’s textarea because i was config it like that and work fine.
and you should clean your script or tag(ensure that all tag was close) before use any WYSIWYG editor.
How do you configure ckeditor to just handle the textarea?
right now in my header I have:
<script type=”text/javascript” src=”ckeditor/ckeditor.js”>
</script>
and then in the body:
<li>
<label for=”content”>Article Content</label>
<textarea name=”content” id=”content” placeholder=”The HTML content of the article”><?php echo htmlspecialchars( $results[‘article’]->content )?>
</textarea>
<script type=”text/javascript”>
CKEDITOR.replace(‘content’);
</script>
</li>
and it shows up, but with everything else from the page inside the ckeditor text box.
First, off this tutorial is great. I am not new to php but new to a project that is this advanced. I tried to alter the code to work with a project I am trying to work on, in an attempt to learn more about php. I’ve added different fields and have edited all of the files. However, whenever I try to post a new article, it says changes have been saved, while my database remains untouched.
Edits to Article class (which I have changed to TechCard:
Other files have been updated accordingly. Like I said, I get no error and everything seems to be working fine. It’s just when I add a new article nothing is added. I know I missed something somewhere.
[Edited by pacothelovetaco on 25-Jan-12 21:18]
@mpierce1001
here is my config.
@pacothelovetac i got some problem like you before maybe check your
name attribute must same as
in admin.php for
PS. i’m new to php. in fact i’m a designer. 🙂
@chotikarn I double checked and they do match.
I have:
and in admin.php:
Thank you for the suggestion. That’s one variable checked.
Thanks for your help, but I cannot fix it.
I am getting frustrated as no matter what I do to try and seperate the form elements everything populates inside ckeditor.
Even the page title the logged in as everything within the content area of the page populates inside the ckeditor.
Help please.
Hy there !
I have a BIG problem here… :'(
I’ve downloaded the zip (did make the sql part too) then rewrote the codes from here. (ctrl+c–>ctrl+v)
Then I got a Fatal error :
“Fatal error: Class ‘PDO’ not found in D:cmsclassesArticle.php on line 104”
So what could be the problem here ?
We already have a code that contains PDO on line 84 if I’m right.
So why the problem is on line 104 if we have the exact same code on line 84 ?
PLS HELP !!
I was able to fix my issue.
It turns out that
Actually should be
Now it’s saving data in the database. But now, I cannot retrieve the data. For instance, in listArticle.php I have:
It finds the ID just fine, but won’t print any other data from the database. Am I trying to retrieve the data right?
@krisee99 If I’m not mistaken, the PDO on line 84 is part of a function that gets called depending on what your are trying to do (ie edit the article). But creating a new article doesn’t call that function, it calls the function with PDO on line 104.
You need to see if you have PDO enabled in your php.ini file.
@pacothelovetaco: I’d recommend using the same field names throughout your script, templates and MySQL table to avoid confusion and potential problems.
eg if your MySQL field is called emp_first_name then make sure your TechCard property is also called $emp_first_name, and that your form field is <input name=”emp_first_name” …>.
The code you’ve posted so far looks OK, so I’m guessing there’s a problem in your class whereby your TechCard objects aren’t getting populated properly. At a guess, it’s because your __construct() method is expecting different $data array keys to the table field names (first, last, empNumber instead of emp_first_name, emp_last_name, emp_number).
So again – make sure you use the same field names throughout your whole CMS!
@mpierce1001: It does sound as if you have invalid markup in your form page, which is confusing CKEditor. Can you view your form page’s source in your browser, then copy and paste the source here? (Use the <> button to wrap ‘code’ markers around the code for readability.)
Also have you tried running the page source through http://validator.w3.org/ ?
Thanks Matt!
It was a markup confusion. The problem was that my <div> containing all the page elements had the same name as the <textarea> I was trying to replace. So CKEditor was just replacing the <div>, thus placing all elements within that <div> inside it’s text box. I changed the name of the <div> and it worked perfectly! Now I’m on to another debugging process. Won’t retrieve my articles continues to display 0 articles. And I tested the CKEditor and it saves the data into my database just fine; its just not pulling it and displaying it anywhere in the site.
Thanks again everyone for your help.
@pacothelovetac Ty for your answer, I’m a newbie here :D.
If I’m right i have it enabled but in case if not how do I check that I have PDO enabled in my php.ini ?
Do i need to have “;” this before the extension or not?
@krisee99 delete ; to enable.
you can use phpinfo() to check your PHP detail.
Hi and congratulations for your great article that led me to my first self-made CMS.
Anyway, I’m facing an issue and you could help me.
Everything is working fine both in frontend and backend, storing and retrieving articles, except for the ‘listArticles’ view.
In that, the server displays “Invalid argument supplied for foreach()” referring to the:
as values are not in array…
I merged your tips with my login system (I excluded your login/logout infrastructure), but I don’t think this is the problem…in fact, everything is ok a part of this.
Thanks a lot for the help you can provide me.
Please help!
I cannot get any articles to be retrieved anywhere on the site.
Everywhere just says “0 Articles” or there is nothing displayed at all.
I have checked everything and it all seems to match consistently with the articles table.
Is there something that needs to be set-up with MySQL to allow the PHP code to retrieve the articles?
Thanks in advance for any help.
<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 was published
*/
public $publicationDate = null;
/**
* @var string Full title of the article
*/
public $title = null;
/**
* @var string A short summary of the article
*/
public $summary = null;
/**
* @var string The HTML content of the article
*/
public $content = null;
/**
* Sets the object’s properties using the values in the supplied array
*
* @param assoc The property values
*/
public function __construct( $data=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()]/”, “”, $data[‘title’] );
if ( isset( $data[‘summary’] ) ) $this->summary = preg_replace ( “/[^.,-_'”@?!:$ a-zA-Z0-9()]/”, “”, $data[‘summary’] );
if ( isset( $data[‘content’] ) ) $this->content = $data[‘content’];
}
/**
* Sets the object’s properties using the edit form post values in the supplied array
*
* @param assoc The form post values
*/
public function 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, $m, $d, $y );
}
}
}
/**
* Returns an Article object matching the given article ID
*
* @param int The article ID
* @return Article|false The article object, or false if the record was not found or there was a problem
*/
public static function getByid( $id ) {
$conn = new PDO( DB_DSN, DB_USERNAME, DB_PASSWORD );
$sql = “SELECT *, UNIX_TIMESTAMP(publicationDate) AS publicationDate FROM articles 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)
* @param string Optional column by which to order the articles (default=”publicationDate DESC”)
* @return Array|false A two-element array : results => array, a list of Article objects; totalRows => Total number of articles
*/
public static function getList( $numRows=1000000, $order=”publicationDate DESC” ) {
$conn = new PDO( DB_DSN, DB_USERNAME, DB_PASSWORD );
$sql = “SELECT SQL_CALC_FOUND_ROWS *, UNIX_TIMESTAMP(publicationDate) AS publicationDate FROM articles
ORDER BY ” .mysql_escape_string($order) . “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 total number of articles that matched the criteria
$sql = “SELECT FOUND_ROWS() AS totalRows”;
$totalRows = $conn->query( $sql )->fetch();
$conn = null;
return ( array ( “results” => $list, “totalRows” => $totalRows[0] ) );
}
/**
* Inserts the current Article object into the database, and sets its ID property.
*/
public function insert() {
// Does the Article object already have an ID?
if ( !is_null( $this->id ) ) trigger_error ( “Article::insert(): Attempt to insert an Article object that already has its ID property set (to $this->id).”, E_USER_ERROR );
// Insert the Article
$conn = new PDO( DB_DSN, DB_USERNAME, DB_PASSWORD );
$sql = “INSERT INTO articles ( publicationDate, title, summary, content ) VALUES ( FROM_UNIXTIME(:publicationDate), :title, :summary, :content )”;
$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->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(): Attempt to update an Article object that does not have its ID property set.”, 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 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( “: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 have an ID?
if ( is_null( $this->id ) ) trigger_error ( “Article::delete(): Attempt to delete an Article object that does not have its ID property set.”, E_USER_ERROR );
// Delete the Article
$conn = new PDO( DB_DSN, DB_USERNAME, DB_PASSWORD );
$st = $conn->prepare ( “DELETE FROM articles WHERE id = :id LIMIT 1” );
$st->bindValue( “:id”, $this->id, PDO::PARAM_INT );
$st->execute();
$conn = null;
}
}
?>
</code>
My blog admin is stuck in maintenance mode.Please help me remove it from that state
Hi,
I solved my previous issue.
I was wrongly calling listArticles.php and editArticle.php by themselves instead of calling admin.php.
Now everything is perfect except for a double quote escape problem.
When I store articles’ content in database, double quotes are wrongly escaped as for example:
Any hint? PDO mysql calls by bindValue() seem correct…
@asnothingelse
i had problem like you before…
my article had many \\ so i use below code to fix it.
add it in config.php to disable magic quote for some host that was enable it.
i think it might work.
@mpierce1001
your code pain my eyes 😀
is it only show “0 article” or none of them showed.
see here
and look in your index.php (or handle function page) for
then check on your include page (archive.php) to ensure that it was echo $results[‘totalRows’].
if it not show any article it maybe other problem.
PS.let’s me know if it not work, i’m just share my opinion for some case that i was face before.
@chotikarn
Thanks for the tip I checked all of that again that you suggested and everything matches. I have checked and checked again all the code that retrieves data and I cannot find any errors.
Any ideas on what else it could be?
Are there settings in the php.ini that need to be configure or settings in the MySQL that need configured?
Thanks for all your help!
@chotikarn
thanks for you hint, but I surprisingly solved my escaping trouble!
I discovered that if I avoid double quotes in the article editor, when I write HTML, the CMS will add by itself without any other errors.
If I write this in the backend editor:
..then I obtai this in fronted:
which is right!
Maybe, this could be brought by the magic quotes of the server setting (I didn’t know about it).
If I’d disable it, like you suggest, probably I could normally write in the editor with double quotes too.
I will try !
[Edited by asnothingelse on 28-Jan-12 10:06]
@mpierce1001
maybe PDO drive does not enable to connect or MySQL
use try – catch to handle PDO connection
this code might help your to check PDO connect to MySQL
in other way try to use Xdebug it’s help a lot to find error.
Note: Xdebug was include with XAMPP just enable it in php.ini.
@asnothingelse
i’m new to php (but not HTML and CSS) then i feel surprise too.
my given solution might not match your problem, but it worthy to try. 🙂
look at php.net for more detail, it was help me a lot.
[Edited by chotikarn on 28-Jan-12 11:03]
Hi guys
I m new to php and this is an awesome tutorial to a real world php app.
Thank you mat for doing this thx alot
I hv a question it may be silly still.
I cnt actually figure out where is the main object of the class Ariticle were made.. cant find a like
outside the class file in any other files.
If anyone can help me understand this that will be very helpful
Thank You
[Edited by avisek on 28-Jan-12 22:06]
@avisek: Article objects are created in 3 places:
In admin.php (inside newArticle())
In Article.php (inside getById() and getList())
Look for the code “new Article”.
Cheers,
Matt
@Matt eww thx i got it now
was a silly question 🙁
thx a lot for the tutorial
This article was amazing! Thank you Matt for your superb work.
Well written and good to learn from!
I’m kind of new to this whole php-thing, but I’m learning from every tutorial 🙂
I have, at this date, included a whole custom CSS, the CKEditor and KCFinder to this work, just to play with, and it works great (after several face-palms and whatnots)!
For thos who are interested, a sample: Guolldo dot com/cms/admin dot php
Now, my next task is to integrate a pagination, and here is where I’m stuck. I have tried to search the web for a good tutorial that I can combine whit the whole cms, but every tut I read ends up with me looking like a question mark.
So..
Can somebody maybe point me in the right direction for some good documentation?
Or, Matt. Have you taught about maybe write a follow-up article with pagination? 😀 I think there are many of us that would be able to learn allot more, and discover new possibilities whit one more good tutorial 🙂
Thanks allot again, and I apologize for my spelling and grammar.. / J
@jj if you would like to add pagination, try this…
first make new function in Class
and then modify our index.php to handle pagination function
i’m need to use it only in archive page, so here is it.
then on the archive page we will render our pagination
just put it on top of archive list of bottom.
it’s not look smooth enough but maybe helpful, and i’m newbie to PHP like you, cheer!.
Note, i have modified original code. maybe have conflict with original code, then let’s me know, if it have any error.
[Edited by chotikarn on 09-Feb-12 11:42]
I wonder should I give that pagination code a try….or wait for Matt’s approval 😛 It’s pretty much the only thing keeping from putting my site live.
G’day Matt.
Absolutely brilliant tutorial on the CMS. It has helped bucketloads in a current project and has allowed me to completely avoid having to use WordPress, Drupal etc.
I am experiencing a problem however. I can add an article, the id, summary and content are stored sucessfully in the DB. However, when I log in as admin, I get a “Notice: Trying to get property of non-object” error that seems to stem from the “editArticle.php” script.
I haven’t edited your code in any way, however – it seems that the article object either hasn’t been created (which I don’t think is the case, as the data is correctly sent to the DB), or there is a block somehwere in accessing the object.
The error repeats on each input line of the form (id, title, summary, content and date) and in the relevant fields where one should be editing, it is spitting out the error tables in HTML format.
I am completely confuzzled, any help would be greatly appreciated.
Any help would be greatly appreciated!
@Matt
I found this webpage/post by accident and I am so glad I did. I have been a coding basic websites and apps for years, but I have always been worried about the security of my code (its pretty unsecure!).
I am going to re-write a few things around this model. I would love to see more tutorials like this one. I took the time to understand how it all works, rather than just download the zip files.
Thanks for this tutorial – I look forward to hitting the forums with any questions I may have!
Ok, so I think I found out what my problem is. I didn’t have PDO enabled in my local php.ini. This isn’t a problem, however – when I uploaded the project to my web host – they also did not have PDO enabled; when questioned if they could enable it for me, they advised that they were not able to due to due to other clients using Curl with SSL support.
So, my new question is this: what can I use in place of PDO? Would a basic DB class suffice? (Obviously losing some of the security that PDO gave). If so, how would that be implemented?
Hello…!
Thanks for the tutorial, its working pretty well here…! I am very thankfull for this…!
Its reading the db, showing all options…!
Then, i made some workarounds that not are running…!
I made a little tip window with JQuery which works with the content of articles…!
I put the scripts in header.php:
<script type=’text/javascript’ src=’http://code.jquery.com/jquery-1.6.js’></script>
<script type=”text/javascript” src=”jquery.min.js”></script>
<script type=”text/javascript” src=”script.js”></script>
all files inside “include” directory…!
When i call cms/index.php in browser all the page source code is the same of original working “index.html”…! But its not showing any effects…! All db/content are below my background image and the footer.php is in the top of page…! The db/content should be over background image with JQuery/CSS effect and footer.php on footer (obviously)…!
How could i include JQuery/CSS effects…?
Thank you.
@Marki maybe wrong path, check your path use debug console on chrome or firebug
belong to your code, it seem to find your file in cms folder.
so try..
src=”/include/xxx.js”
[Edited by chotikarn on 14-Feb-12 01:58]
@chotikarn: Thanks for posting your pagination code 🙂
@DOC: Looks OK to me though I haven’t tested it. I would do it slightly differently by using getList() but the basic idea looks sound.
@jj @DOC: I’m certainly planning a follow-up article on pagination. Just to be clear: When you guys say “pagination”, do you want pagination of the homepage and archive page (anywhere that lists articles basically), or the ability to split actual articles into separate pages? I’m guessing the former rather than the latter?
Cheers,
Matt
@Matt Ya I had the pagination of article listings in mind but I guess I can’t speak for everyone. I remember coming across a little jQuery sample that does the latter.
Thanks again.
chotikarn:
Thanks for reply, you solved my little prob…! It was the path of files…!
TY.
@Marki
i’m glad to hear that your problem was gone.
@Matt
i sound good to me to see “split actual articles into separate pages”.
Thank you again. 🙂
@oxygen: Thanks for the feedback – I’m glad you found the tutorial helpful. Good luck with your sites 🙂
@BlackhawkNZL: Hmm, that’s strange. PDO is pretty standard these days.
You could try MDB2, which is sort of a PEAR counterpart of PDO:
http://pear.php.net/package/MDB2
http://www.procata.com/blog/archives/2006/12/26/pdo-versus-mdb2/
It’s all pretty similar stuff really – connect to the database, prepare an SQL statement, execute it, then fetch the result rows.
@DOC @chotikarn: OK, it sounds like you want both list page pagination and article page pagination! 🙂 I’ll see what I can do. I’ll probably do list page pagination first as I suspect that’s more in demand…
it’s sound great, i can’t wait for it! 😀
Any idea why an article’s publication date would decrease by a day every time the Edit Article form is saved? This didn’t happen with the initial tutorial files, but it started happening after I added a few fields to the database and corresponding code. I’ve checked all the files a dozen times. I haven’t changed anything pertaining to the publicationDate at all.
I got everything working except for the stupid date.
@SpitZu: Off the top of my head, that sounds like a timezone mismatch between PHP and MySQL. Check that the date_default_timezone_set() call in your config.php is setting the PHP timezone to your server’s timezone. If it’s correct, check MySQL.
Hi there, again, this is a great tutorial, got my CMS running nicely on my band’s website, http://www.demob-happy.com/
I do have one issue that one user kindly pointed out to me. He mentioned that I was not capturing exception errors in my article class which in turn outputted the connection string along with the database username and password details like so:
My site is working fine and this was the first that I had heard of this error, maybe the database was under heavy load opening and closing connections? So I then changed the article class to use persistant connections. The user who pointed this out then sent me a link to the php.net page on PDO connections.
http://php.net/manual/en/pdo.connections.php
Which mentions…
“If your application does not catch the exception thrown from the PDO constructor, the default action taken by the zend engine is to terminate the script and display a back trace. This back trace will likely reveal the full database connection details, including the username and password. It is your responsibility to catch this exception, either explicitly (via a catch statement) or implicitly via set_exception_handler().”
So how would I implement this in the public static functions that grab the articles from the database??
Hi Matt and all other people discussing here on this amazing tutorial!
I have few questions once again..
1. What do I need to rewrite in the code and where if I want my articles to be sorted by the time and date they are written, but that the newest appears on top, instead on the bottom as it is now
2. What do I need to change if I want more than 5 articles to appear on the page
3. Is it somehow possible that I have one row in which I can upload a simple photo in the article. Let’s say that I have two photos -> photo1.png and photo2.png
So i would like, depending on the article, to have the possibility to choose which photo to put somewhere in the article
Thanks!
[Edited by Janjetina on 22-Feb-12 06:25]
@Janjetina
1. if you need to sort your aticles with time newest to oldest.
first, you need to change your “publicationDate” column in “articles” table to “Timestamp” and default must be “current_timestamp”.
second, deleted whole <li>..Date.. </li> in editarticle
[ edit – i mean change type from “Date” to “Timestamp”]
now your CMS will order articles by time and date.
2. figure out in config.php find
now the number on your desire.
3. you can done that by use Ckeditor and Ckfinder. i have been done it before work like a charm.
[Edited by chotikarn on 22-Feb-12 08:49]
Big thanks chotikarn
I will post back when I’m done and when it will work, but from my position right now, can you please refer me to somewhat more instructions regarding my third question about pictures and the answers You have given to me
@Janjetina
as your pleasure… this will add your both Cover image for your article and can add picture to your article content
first of all you need
Ckeditor and Ckfineder(it’s demo but fully function)
google will help you find it.
Then, put your Ckeditor and Ckfinder folder to your root dir and open your editarticle.php
in your <head> tag add
and
that is simple setup for Ckeditor and Ckfinder
now go to your form add this code before form
and add id=”content” in <textarea name=”content” /*add here*/></textarea>
and add new input element
————————
now we will move to work with Class file open it
and add
now we’re almost done
go to your database and add new column
coverimage VARCHAR 255 not null
it might work now.
to add image in your article just add by use button in Text Editor
and click “brows serve” to upload and select
to add cover just click “Brows Sever” and file path will store in to your database
———————-
move to front-end , index.php
in foreach add
now you have both Cover image and image in articles content.
PS. let’s me know if you confuse or have any problem
[Edit – only spell check :D]
[Edited by chotikarn on 22-Feb-12 10:25]
Dear chotikarn, before I check this with photos, can please be more precise about my first question, sorting newest to oldest..
Can You please specify what changes need to be made and exactly where because I’m not able to make them work right now
🙁
Wow chotikarn!
This was an amazing tutorial for images, it works!! 😀
Now i just need to fix this sorting by time…
@Janjetina
i’m sorry for unclear suggestion.
you need to go to your database by use something like “phpmyadmin”, then select your database (which have “articles” table in side).
now, on “articles” table and click on “structure” and then look for “publicationDate” field/column, click “Change”
in new window change Type: to TIMESTAMP and default to “CURRENT_TIMESTAMP”.
ok, now it’s quite clear, right? and i’m very glad to hear that your image work fine.
ps. sorry for my bad english.
Now it’s clear, I’ve done it but it doesn’t work….
maybe i need to change something in my .php files?
You’ve mentioned doing something in the editArticle.php
[Edited by Janjetina on 23-Feb-12 04:27]
@Janjetina
just delete those code, we do not use it anymore because we use MySQL to automatic insert current date and time instead of fill it manually.
[Edited by chotikarn on 23-Feb-12 06:30]
Works great!
🙂 🙂
Many thanks!
Hello, I had a bit of a problem implementing characters like öåä. So I used strtr like so.
Would this be suggested, or should I be using preg_replace?
Also I would like to ask you if your thinking about doing the image upload tutorial anytime soon, if your going to do it.
Been messing around a bit with it this last weak but im having a real problem understanding the things going on in article.php.
I already have the image upload function written, it creates the thumbs and all that. Im just having a problem implementing it with the CMS!
@AdamBarry: Oops, good catch! (Pun not intended.)
The easiest workaround would be to add this to your index.php, just below the config.php require:
That will handle all exceptions, including any returned by PDO, and display a generic error message instead. Not the most elegant solution, but it will prevent the problem you describe.
The more elegant, though long-winded solution would be to add try…catch blocks to every PDO call within Article.php.
I’ll update the tutorial.
Cheers,
Matt
@srtu: Try this for a utf-8 version of strtr():
http://stackoverflow.com/questions/1454401/how-do-i-do-a-strtr-on-utf-8-in-php
Will hopefully write the image upload tutorial some time soon (can’t say when!).
Well i have accomplished to show a “Categories Menu” by doing this:
I Hope this helps somebody.
Amazing Tutorial really
Just so you know, the Config2.php contains the code to connect to the database.
Great tutorial. Still working from your source, and implementing some changes given by other readers.
q1: in phpinfo of my webhost I search for magic and get:
magic_quotes_gpc On On
magic_quotes_runtime Off Off
magic_quotes_sybase Off
first state is local value, second being master value.
The wording is confusing me, I assume I am safe and magic quotes is off
q2: Anyone want to share how they implemented hashing?
And for those who are wanting to integrate comments, I personally, prefer just to use an external service, like disqus. Integrating there system is easy and safe. Just add the code to viewArticle.php
Thank you again for a great resource.
managed to work out hashing:
My admin.php function login is as follows:
I chose to hash the username as well, and will probably add a second password. This is a single admin site, so I can stand to use multiple passwords. Not sure if also hashing the username helps at all with obscurity.
To avoid posting the username to the site, I change the function to ADMIN_USERHASH. I added a generic value to ADMIN_USERNAME, ie. “WebMaster”.
To generate the hash values to place in config.php, you need to create and run a php file ie. hash.php
Save this file somewhere safe, not on your webserver, after you generate your hashs.
My config.php looks like this:
My algorithm uses “salt”, which helps further protect your information. I also am using sha512 to generate the hash, because, it seems the most secure algorithm PHP supports.
Hashing the username is completely optional. I might be overly paranoid. Forgive my lack of expertise, I am just now learning this stuff, as well. I hope this helps someone, I had a long day going thru alot of web pages to get this far.
@csturner
Thank you. i’m looking for something to arise my site’s security.
let’s me explore your code, it might suit my site some way.
thanks again. 🙂
Hello,
What kind of licence this CMS holds?
Thanks 🙂
Hi all again 🙂
I have got one practical question.
All my articles are being saved on the archive page. What if one day let’s say, I’ll have 2000 articles. Would that mean that all articles will be saved on one page -> archive.php and you’ll have to scroll to get to the first one which will be on the bottom or is there any way that they could be managed and sorted by month?
If I want a thumnail picture on the mainpage (overview) and the main picture in the details page, would that be much work?
I started working out a way to add images and I have it working with minor bugs. But I’m no PDO expert so I’m curious if there is an easier way.
First I created another column in my database called ‘photo’ with a type of LONGBLOB.
In editArticle.php, I have :
Then I updated Article.php accordingly to add the new column. Under update(); (just working on this function for now), I added:
It seems to be added to the database just fine. I know getting it to show in the article will be another challenge for me, and I’m aware that my current code has some bugs. Putting that aside, is there an easier way or am I on the right track. Ideally, I would like the database to store the file name so that it is easier to retrieve. However, I couldn’t get it working using PDO.
What about doing a Autoload class, then we won’t neeed to require pages…
Maybe someone knows how to do that?
I’m sorry, I’m having a problem with database connection
im useing appsever
can you please fix it for me
Fatal error: Uncaught exception ‘PDOException’ with message ‘invalid data source name’ in C:AppServwwwcms_classesArticle.php:103 Stack trace: #0 C:AppServwwwcms_classesArticle.php(103): PDO->__construct(‘DB_DSN’, ‘root’, ‘root’) #1 C:AppServwwwcms_index.php(40): Article::getList(5) #2 C:AppServwwwcms_index.php(14): homepage() #3 {main} thrown in C:AppServwwwcms_classesArticle.php on line 103
@csturner: No, you want magic_quotes_gpc to be off, otherwise quotes in data sent from your forms will be escaped. Or if you can’t turn it off, you can test for it and run stripslashes() as I indicated earlier:
http://www.elated.com/forums/topic/5114/#post21628
I tend to agree with you that Disqus etc is a nice solution (and a lot easier!). However I might still write a comments tutorial just to show how it’s done.
Also, nice hashing solution 🙂
@user89: It doesn’t have a formal licence. Essentially though, I’m happy for people to use and adapt the code as long as they include an attribution and link to the article ( http://www.elated.com/articles/cms-in-an-afternoon-php-mysql/ ) somewhere that’s publicly visible. I guess it’s essentially similar to http://creativecommons.org/licenses/by/3.0/ . I might formalise this at some point.
Really though, this code is simply meant to be a tutorial to teach you how to use PHP and MySQL to build a CMS. I hope that readers can take the ideas in the tutorial and use them to build their own, more fully-featured CMS that suit their needs.
mod_rewrite is giving me a migraine. Why does every iteration of software have to change the rules?
I’m just trying to go from http://#######.com/?action=viewArticle&articleId=1
to something like
http://########.com/2012/02/29/titleofarticle
That is the proper way to improve seo, right?
@csturner
i have done something like this
before $ is new look of our url, and after that is old look (real format of our url).
([^/]*) mean match any character.
this we will have
instead of
and php generate our link would like
i’m use str_replace(array(” “,” “),”-“,$str) to replace space and double space with -.
if you need some thing of that you want.
change mod_rewrite to
/articles.php?action=$1&articleId=$2&year=$3&month=$4&day=$5&url=$6 [L]
and new look
^articles/([^/]*)/([^/]*)/([0-9]+)/([0-9]+)/([0-9]+)([^/]*).html$
*([0-9]+) match only number with 1 or more
and your php generate link would like this
we still need article’s id because we look up our MySQL through id.
final result of your link
xxx.com/articles/view/12/2012/03/02/title-of-article.html
look like real static link!
may be you can move our id to show with url like
“12-title-of-article.html”
just change arrangement in link and mod_rewrite.
ps. hope you understand my english. 🙂
another ps. i haven’t test ([0-9]+) regex before.
[Edited by chotikarn on 01-Mar-12 21:04]
@AdamBarry (and everyone else): I’ve just updated this tutorial and http://www.elated.com/articles/add-article-categories-to-your-cms/ to include the exception handler in config.php, so that PDO exceptions are never displayed on-screen. Code downloads also updated.
Thanks for you tutorials.i followed everything that u said and after i have hosted it on my server,this is the error message that i receive.pls assignment me…
=================================
Fatal error: Class ‘PDO’ not found in /var/www/ip/ex1/cms/cms/classes/Article.php on line 104
=======================
Expecting ur response soon.
Thanks…
@matt
thanks for your update.
@boge123
look like your PDO extension doesn’t enable yet.
How do you allow multiple users? Also, is it possible for free registration and permissions for each member?
@matt how can i do that?..pls guide me. expecting your response.Thanks…
@Matt Hi i have a question it is a bit off topic still
Q) I saw many hosting provider provide mysql db with 1GB space
and with unlimited plan you get like 1GB unlimited amount of db. As you can see the space is 1GB for each db then how can i move to another db or when the 1GB space is full.
I mean do i hv to make new db and manually check for db space and if i need to make new db how do i access it cos i hav for instance two db to access data.
How do big website cope with this problem 🙁
Thx Matt for the tutorial again
Matt, excellent tutorial.
From reading through all the comments above (including some of your helpful hints) I’ve been able to piece together how to successfully upload images in the back end and view them in the front end – although it took me a while as I’m really no expert. I wondered if you could give me any suggestions on how to hide any empty image fields (more difficult than hiding a text field).
Here’s the code I added to the homepage to retrieve the image file..
Any hints would be gratefully received. Thanks again for posting this tutorial.
Chris
@Janjetina: I plan to address pagination in a future tutorial. See comments earlier in this topic.
@liholen: Shouldn’t me much work. I plan to address image upload in a separate tutorial.
Autoloading will only load class files. Since there’s only 1 class file in this tutorial, autoload would be overkill.
@pacothelovetaco: I never store my images in a database. Just store them as image files in the folder, and store the image filenames in the database table.
It’s certainly possible to store images as blobs in the database, but I wouldn’t recommend it. Let the web server serve the image files – it’s what web servers are good at 🙂
I added some hints on image uploading earlier in this topic.
@phaohoa: Sounds like you haven’t defined the DB_DSN constant in your config.php, or you’ve quoted the constant name in your PDO call.
@adityasaky: You mean multiple admins? I mentioned a hack for 2 admins here: http://www.elated.com/forums/topic/5391/
If there’s enough demand for full-fledged multiple admin support then I may write a tutorial on it.
I don’t understand what you mean by “free registration and permissions for each member”.
@chotikarn, but how do i enable it.pls guide me.Thanks
first check your php information by
creat new php file name phpinfo.php
and add this code in it
if your PDO was Enable you will find it.
if it not enable yet, you should to config your php.ini by delete semi-colon in front these line
extension=php_pdo.dll
extension=php_pdo_firebird.dll
extension=php_pdo_informix.dll
extension=php_pdo_mssql.dll
extension=php_pdo_mysql.dll
extension=php_pdo_oci.dll
extension=php_pdo_oci8.dll
extension=php_pdo_odbc.dll
extension=php_pdo_pgsql.dll
extension=php_pdo_sqlite.dll
more information should be here.
http://www.php.net/manual/en/pdo.installation.php
@chrisbailey: Just use a conditional statement, for example:
That way, the img tag won’t be added to the page if the ‘image’ field is empty.
I want to use tbl_articles instead of articles.
Will I only need to change SQL statements i.e.:
to
can i ask the username and password of the admin? cant open the open the admin page…and also the index, won’t run…can somebody help me?
Read the code in config.php and you will find it there!
Oh and!
Make sure you change it if you are deploying the CMS on a live server.
@michaelgc: Yes.
@matt, by free registrations, I meant anyone should be allowed to sign up to the site. And permissions as in, some may have permission to post, while others can edit. Like that.
This post is probably a bit late but my exams are on! Sorry.
Is it possible to produce the list of archived articles in the header, so that there is an instant access to all the articles on a sidebar while still producing results for each of the pages? I’ve attempted the following.
While each function in the index and admin files not using getList has been modified with:
But it registers the Limit set by the homepage.
[Edited by ares on 24-Mar-12 09:43]
Hi again!
I have encountered another “problem”. Well everything is working fine with the ckfinder and whatnots, but I had an idea when I saw the new “add article categories” to the cms.
My idea is kind of basic really, its about echo out the different Article Categories to the header in links, like:
so the user can change the names of the categories easy.
Its working without any problem, but when I access an Article, The “<?php echo ( $results[‘categories’][$article->categoryId=3]->name )?>” (or echo name of category) does not work, and it displays blank.
Ive tried to configuration the Index, but no success.
For an example of what i mean, visit: guolldo (dot] com/cleancode/
and click on a Article, and look in the header-menu.
Can anyone help me figure this out or maybe give any hint? 🙂
And Matt, this tutorial have enlighten me with the whole mysql & php combo and possibilities, its awesome! THX 4 M!11!0n!!
@jj
You can achieve what you want with this code. Please note that config2.php is the file containing the info for the database.
Hope this helps
@adityasaky: Well you’d need to build a Members table and Member class, with methods to allow registration and login/logout. Add a ‘permissions’ property to the class to specify what the member can or cannot do.
Excellent tutorial, I’m close to getting it to work (had a slight slip up on the kb), thanks a lot for your insightful tutorial. 🙂
@ares: No idea without seeing all your code. The snippets you posted should work. Perhaps $results[‘articles’] is getting overwritten by the shorter list later in the index.php code?
Thanks for the reply. As you said it was overriding, I would need two separate arrays for it to work in the index, so I ended up solving it by removing the article limit, and adding a loop-break clause with a limit in the homepage.
Hi,
I have had a good mess around with the code but have got a little stuck trying to modify…
I would like to add an author id which is an integer, so I created the field in the database but am not sure how to get the author string to update as the correct author id when adding to/modifying the database.
I have:
but don’t know how to pass the author name into the variable author1.
When editing a record it works to just get $results[‘article’]->author but when adding a new record that textbox is not populated until it is $_POSTed.
I also changed the Article class to include
[CODE]$st->bindValue( “:authorID”, $this->authorID, PDO::PARAM_INT );
and other places like that, I have managed to get it to add to the database, but not populate the authorID column.
Thanks for your time, I hope I explained well enough
[Edited by AWE on 29-Mar-12 18:40]
@Matt
hi matt, hope u doing good.
i went through the forum , to check wheather my question was answered before.
Our CMS get the news articles first. order by date DESC.
but what about if publish 10 articles a day and i want that the news article displayed at the top of the page by time. For example i published 10 articles today, date is same. But different hours and i want to see the news articles by time (hour) displayed at the top.
As we have already got date field in our database, i wonder wheather i could modify or need another additional field which holds my timestamp.
headlines.
>Microsoft anounces IE 9 date published and time.
>Microsoft anounces IE 10 date published and time.
>Microsoft anounces IE 11 date published and time.
Thanks
@mubuuba
i had finish modified code to handle date and time, and have a hint to other guy in this topic.
but you need to show only today article
MySQL might help you, here to code
“WHERE publicationDate = CURRENT_DATE”
you can also use GROUP BY to count number of your today article.
@Matt, I want people to be able to register directly using a register form. Can you do a tutorial on that?
HI guys,
Awesome tutorial, it was really helpful especially how you went through most of the lines of the code.
Im having just one issue (i think). Im running the site on my MBP by using XAMMP. When i view the site i get this message
“Sorry, a problem occurred. Please try later.”
i have gone through the code a few times now trying to work out where i went wrong. Im about to download the demo site to see if i can get it working that way.
Thanks
Jason
@jasonf
Open the config.php -file and look at these lines:
Your username is probably “root”, and if you have not created a password, then let it be blank.
Also, if you havent, create the database in phpmyadmin with the .sql file 🙂
——–
@metalsniper63
Thank you for the code, but it is not working for me.. 🙁
I think it is because I have used the “CMS with Articles”-tutorial.
Maybe any other idea? 🙂
Best regards,
JJ
@jj
Thank you so much it worked. I had the database name right it was just that my user name was “root”
thanks again
Jasonf
@metalsniper63 & everybody else that are interested 🙂
I’m trying to echo out the category names as links to the different categories in my header in a smart way, but I can not figure it out 🙁
Maybe any suggestion on what to do?
I’ve used the code from: metalsniper63 (Thanks btw 🙂 )
And it gives me:
“Fatal error: Cannot redeclare handleException() (previously declared in /Sites/the_site/config.php:15) in /Sites/the_site/config.php on line 18”
When I investigate the problem in config.php, I find:
(code included in the cms with articles)
But, as I am (still) very new to PHP, and got no one to ask, I try to reach out here to solve this problem 🙂
Anybody who’s got an idea of what to do?
Best regards,
JJ
@jj
Well what i would do (and did) is to create a new config file (with i called config2.php) with only the info to connect to the database:
It should now work with my code, just include config2.php instead of config.php.
Also i have this little code to show a “recent post” menu:
Again this uses the config2.php file.
Hope this helps you and anyone who wants it
You can see it working here: http://www.standartdgo.com in the Blog section.
I have also added a Comments box from Facebook that changes for every article, if you want it just tell me 🙂
[Edited by metalsniper63 on 04-Apr-12 10:26]
@metalsniper63
Woohhaa! Or as we say in Swedish ‘Fan va gött!’.
That did the trick. I just called in a db connection and executed the php, really good. Thanks amillion! 😀
I’m really interested about the Facebook-comments box 😀 I have right now a dynamic Facebook ‘Like’ button, and a Tweet. If someone is interested, let me know also. But if I also can add an dynamic comment field it would be darn awesome!
I think you will help out allot of people with that code, caus now I start to understand the brilliance of PHP + MySql, it cool!
Thanks again!
Best regards,
JJ
Ok for all that want Facebook comments on your articles here is the code:
I didn’t make this code, i just don’t remember where i got it from hahaha. just change the “script src” line to your local script and that’s it.
I placed this code in the viewarticle.php file. i think is really self explanatory. Happy coding
@AWE: Not sure I understand totally. Sounds like you want to have different article authors, yes? The best way would be to create an authors table with unique ids and author names and create a corresponding Author class, then add an authorId column to your articles table and a corresponding $authorId property to your Article class. Then in index.php etc you can call Author::getList() to get all the authors and store them in an array keyed by ID (much like I show with categories in http://www.elated.com/articles/add-article-categories-to-your-cms/ ). Then, whenever you need to display the article’s author, just use something like: $results[‘authors’][$article->authorId]->name .
Does anyone know how i can get the form in editArticles to have a field which had a drop down menu which is populated from a different database with a list of items?
ian
Does anyone know how I can make the publication date in to a drop down menu?
Hi!
Firstly, thanks for an amazing tutorial! I’ve adapted this for heaps of uses (comments/images etc.) now I’m trying to do something probably pretty simple but just can’t seem to do it elegantly..
I want to simply be able to make a post a primary post and want it to display first : Ive tried this by using a column in my DB setting a specific row to PRI. Can I write an SQL statement to update a value of a row while sort of deleting another (so when a new post is set PRI the old one is no longer PRI),
Hope I’m making sense and thanks for any help 😀
Jarrod.
after i run this code in xampp installed on windows os it shows a error message (‘system error try again later’).
please help
@shev
Dude, check out the config.php – file, and enter the correct username, passw & DataBase-name. For Mac os, the default uname is root, and no pword.
Try it out! 🙂
/J
Hi Matt, this looks like a fantastic facility thank you very much.
The only small problem is that I cannot even pass go. I get the message
“Sorry, a problem occurred. Please try later.”
I have searched the forum and the only other example was solved by a user name and password issue. This does not appear to be my problem. Here is my config file.
<?php
ini_set( “display_errors”, true );
date_default_timezone_set( “Africa/Harare” ); // http://www.php.net/manual/en/timezones.php
define( “DB_DSN”, “mysql:host=localhost;dbname=cms” );
define( “DB_USERNAME”, “root” );
define( “DB_PASSWORD”, “” );
define( “CLASS_PATH”, “classes” );
define( “TEMPLATE_PATH”, “templates” );
define( “HOMEPAGE_NUM_ARTICLES”, 5 );
define( “ADMIN_USERNAME”, “admin” );
define( “ADMIN_PASSWORD”, “mypass” );
require( CLASS_PATH . “/Article.php” );
function handleException( $exception ) {
echo “Sorry, a problem occurred. Please try later.”;
error_log( $exception->getMessage() );
}
set_exception_handler( ‘handleException’ );
?>
I do not have any spaces at either end of the file.
I set up the database and fields using the sql file provided and do not have a password for my root user.
Any help will be appreciated.
Many thanks
function handleException( $exception ) {
echo “Sorry, a problem occurred. Please try later.“;
error_log( $exception->getMessage() );
}
Read the error log to see what caused the exception.
Hi,
I tried adding an upload/download feature on your CMS, but it doesn’t seem to work for me, i’m a PHP MYSQL newbie, and i want to learn more… I’m trying to make each topic be able to upload any file, for example, a word document, for users to download..
Thanks for this article, i learned many on this, including on PHP classes, functions etc.
Or if you have extra time, can i request an additional article for adding an upload/download feature on your CMS in afternoon.. please…
Thanks,
MARK B.
@chrishirst
Thanks for the reply. I am too much of a newbie to know how I can go about reading the error log. Further advice would be appreciated.
Many thanks
error_log is a text file (no extension) that is located in the root folder of your website that PHP can/will/does write information about non-fatal errors and exceptions.
It should tell you what the code tried to do and the script that it occured.
@snookian: Depends on exactly what you want to do, but generally I would create a class that maps to your database table (much like Article.php maps to the articles table), and add a getAll() method that retrieves all the objects from the table. Then call getAll() whenever you want to display the form, and loop through the resulting objects to display your select menu. You’ll presumably also want to add an “object id” field to your Article class to associate the selected object with the edited article (assuming that’s what you want to do).
@Micheal: Again, there are many ways to do this. You’ll probably find that something like this is the easiest: http://jqueryui.com/demos/datepicker/
@alteran: By PRI do you mean the table’s primary key? Primary keys are for uniquely identifying database rows – you should not use them for anything else. If you just want a particular article to always appear at the top of the list then create a “primary” boolean column and set it to true or false, then order your results by the primary column, followed by date (eg “ORDER BY primary DESC, publicationDate DESC”).
@markbaronelated: I’ve added file/image upload to the list of future tutorial ideas. 🙂
@chrishirst
Thanks for the help.
The php log is as follows;
[23-Apr-2012 12:05:26] could not find driver
While the access log is as follows;
127.0.0.1 – – [23/Apr/2012:12:05:24 +0200] “GET / HTTP/1.1” 200 6570
127.0.0.1 – – [23/Apr/2012:12:05:26 +0200] “GET /cms/ HTTP/1.1” 200 44
I use WAMP 5
php 5.2.3
Mysql 5.0.41
STOP PRESS ………
Good news is that I have sorted out my problem. Just upgraded to WAMPSERVER 2.2 which sorted the driver problem.
Bad news is that I lost my databases in the process, but I should manage to reconstruct.
This CMS utility looks fantastic. Thank you very much
[Edited by Zimbo on 24-Apr-12 08:37]
Warning: require(classes/Article.php): failed to open stream: No such file or directory in /var/www/cms/config.php on line 12 Fatal error: require(): Failed opening required ‘classes/Article.php’ (include_path=’.:/usr/share/php:/usr/share/pear’) in /var/www/cms/config.php on line 12
hi guys,am getting the above error after following your steps to the letter. help please
And are you running PHP on Windows?
nope…am running apache2 on linuxmint. but i also tried the project on win7 and xampp and still got the same error. any way around it?
Windows I can understand because of the different folder/drive structures. Mint, I don’t know what the default paths are yet as i’m just setting up my first mint box up, 😀 Centos is normally my weapon of choice when it comes to Linux. Is “pear” installed and on that particular path?
[Edited by chrishirst on 25-Apr-12 12:40]
Hi all,
This is a great CMS, but i’m having some issue with using youtubes code for embedding youtube videos.
I find that when I save to the database it adds “” all the way along the embed code
Is there anyway of stoppping this from happening?
Thank all
David
[Edited by slayerscout on 26-Apr-12 20:13]
Great tutorial.
Question about Admin login link on the webpage.
The Admin Login (site admin) link is currently on the same page as blog template.
Can I implement a seperate login page that is not viewable to the public, just to add another level of security. Basically, when I update by webpage/blog contents, I do it via a different personal page.
Hey, first of all, thanks for the great tutorial, it’s helped me a lot, but unfortunately I’m having one problem currently (Similar to slayerscout’s)
http://justanotherrandomsite.com/ I’ve uploaded it to my site, but when I create links or (‘s) it keeps adding “‘s” in the code.
It also messes up the links so I can’t link to anywhere, because the links come out like (ex):
(When linking to http://www.vgchartz.com
I didn’t have this problem when developing on my PC, but now the website isonly and it occurs. 🙁
Any help would be appreciated, thanks.
Hey Matt,
Thanks for the great tutorial! I am in the process of learning web programming mostly from books and articles I am reading online. To help me in the process, I am actually taking the time to type the code myself instead of cutting and pasting. This is what I’ve done with your tutorial, and everything seems to be functioning okay except I can’t get the articles to post to my database. I’ve checked the code several times alongside your original code. Everything seems to match up perfectly. Still won’t post to the DB though. I either get the success message when I use the CMS as coded in your original example, or the “Please fill out this field” callout message appears on the upper left corner of my browser (Firefox) when I try to integrate tinymce with the form. Any ideas on where I am going wrong?
Thanks again!!! It always amazes me when people with your great skill take the time to write comprehensive tutorials like this one to help teach us “newbies”.
@revjeff7
hi, about your problem. it seem that you have “required” parameter on your “textarea” tag. this should be work fine without any Text Editor such TinyMCE or CKeditor, but when you need to use it on textarea the “required” parameter have to remove.
if you still have “required” and have Text Editor, HTML will assume that textarea has on data on it and “Please fill this field” will appear but on my chrome 17 everything look freezing, not have any sign of error.
PS. hope it might help you.
[Edited by chotikarn on 04-May-12 19:23]
@chotikarn
Thanks! You were right about the “required” parameter with tinymce. I guess I need to look for a way to get around this and still be able to use the required parameter on the form. Also, I still can’t get articles to post to my database.
@revjeff7
maybe jquery form validation might help.
do you re-check your code yet? re-check your typo “__construct” functioin “storeFormValues” and “insert” function.
Hi, I was wondering what I would have to edit to make it so instead of just year/month/day, I could make it year/month/day at HH:MM. I thought I had it down, but whenever I try it, it just displays the epoch. Any ideas?
@slayerscout @MarcusS: Search this topic for “magic quotes”.
@vman: You could bookmark the link, then remove the link from the front-end template. If you’re still worried about security, you could password-protect your admin script like this: http://www.elated.com/articles/password-protecting-your-pages-with-htaccess/
@ffxpwns: Here’s the syntax for the PHP date() function: http://php.net/manual/en/function.date.php
@ matt
Thanks for the advice, I found the solution yesterday earlier in the topic. 🙂
Dear Matt.
First off let me thank you for your wonderful, concise and clear method of teaching. I am currently studying Networking and Administration at university and wanted to branch off and learn some PHP. I will defiantly be sharing your website around.
Following on from http://www.elated.com/forums/topic/5114/#post20643 I have pieced together a similar method to upload images in the editArticle.php however it appears that once I insert
Into the function () Insert and update, the entire article refuses to save to the database, and transfers me back to listArticles.php admin page without saving.
Article Class
ImageId is defined as
In __construct, imageId is as follows
In the function insert () and update ()
I have a feeling that the way I have gone about the code to move the uploaded file is incorrect. Should it be under its own function INSIDE function insert/update? Should it come before or after $st->bindValue( “:imageId”, $this->imageId, PDO::PARAM_STR );
editArticle.php
Inside editArticle.php, I have added the form/multidata tag, as well as
Inside viewArticle.php, I have added the <img> code. Which is correct?
Now what I believed this would do, is it should send the results/location to Article::ImageID, which should then use the code in the Article class to send the image filename and location to the database field ImageId, (varchar(255)) which would then be fetched, along with the rest of the article, when that article is clicked on. What I believe and what I know though are two different things.
I’m not sure how much you could help me with just this code alone, I believe I am missing some pretty crucial code, but I have no clue what. When I SELECT * from articles; in mysql, the imageID field is blank.
Please and a massive thank you in advance if you could give me a hint as to what am doing wrong.
Any chance of you doing a tutorial on adding images or other media to the CMS articles.
@MarcusS: Glad you got it working!
@Farmman64 @jpkelly: I’m currently working on a followup CMS tutorial (due next week) that shows how to upload a single image for each article.
Problem:
<a href=\\\”
In index.php insert the code:
<?php
if (get_magic_quotes_gpc() == TRUE) {
ini_set(‘magic_quotes_gpc’,’off’);
Welcome the http://rotflonline.pl
[Edited by rebelianto on 19-May-12 15:18]
Great news Matt!
Looking forward to the new tutorial on adding an image to articles.
Hello All…!
Very nice CMS system…! Works fine here…!
But, i want to add multiple admin accounts with DB…and not calling a solo “username” and “password” account from config.php…!
How to construct a multiple admin account based on DB using this plataform (CMS)…?
Basically this workaround is ready…but, i couldnt see a simple form to do this…!
Need some help, example or tut…simple and elegant as this tut…!
Thank you.
Any word on the progress of the adding images to articles tutorial?
Haha Kelly, im the same with the wondering. We shouldn’t push and pester Matt though, he is doing this out of the kindness of his own heart!
Looking forward to it though!
Sorry…. 🙁 I don’t want to pester or be pushy.
Sorry for the wait guys! It took longer than expected, but here’s how to add image uploads to your CMS. 🙂
http://www.elated.com/articles/add-image-uploading-to-your-cms/
Enjoy!
Matt
Big thanks, matt. your image upload are work well one me.
but i’ve a question about multiple checkbox.
i’ve multiple checkbox look like this
and need to store it’s value in same column of table, is it a good idea? and how should it work on your CMS.
Thanks, Chotikarn.
Hi Matt,
First off I wanted to say THANK YOU for making this, I scoured the internet looking for a decent and easy CMS system and found yours.
Second off, I am a noobie programmer when it comes to PHP and MySQL, but I am having issues with the CMS system working and I’m not sure what to do.
http://pieforensic.com/test/admin.php
That is the link, however when I log in I get “Sorry, a problem occurred. Please try later.”
I’ve setup the DB username and password correctly and I’m using the built in PHPmyadmin panel from host excellence to edit the settings for the db, which is called “sgold39_cms.”
I’m not too sure why it’s not connecting.
@Marki: See http://www.elated.com/forums/topic/5114/#post22468
@chotikarn: I would probably create 3 separate boolean fields in your articles table (red, blue, green), unless you want to have an arbitrary number of colours per article, in which case I’d create a ‘colors’ table and join it with the articles table.
@lowestofthekey: You could try commenting out the set_exception_handler() line in config.php to see the actual error message, or look in your website’s error log for the error message.
Thank you, matt.
My question might not clear.
it’s a multiple choice of checkbox.
i was try to “implode” value together but in MySQL filed still have “array” not “red,gree,blue” as i expected.
and i was try “serialize” and have something like “s:00 { red, green,blue } a:0”.
any idea?
———– Edit ————-
Now, i’ve done what i want but i use another hidden text-input and use jquery to map my checkbox value as array and send it to text-input, then use your cms engine to store it in mysql
it’s work well.
[Edited by chotikarn on 15-Jun-12 13:36]
Matt
You write awesome articles. Could you please show an example of the proper use of Try …. Catch?
Thanks
Phil
I Matt!
I’ve seen you made this:
Well, I would just ask you, instead of calling the “deprecated” mysql_escape_string, why not just go straight with PDO:
?
From the PHP manual:
The parameters to prepared statements don’t need to be quoted;
the driver automatically handles this.
If an application exclusively uses prepared statements,
the developer can be sure that no SQL injection will occur (however,
if other portions of the query are being built up
with unescaped input, SQL injection is still possible).
Please tell me if I’m in wrong!
Bye, best wishes.
Hi Matt
Thanks for the great script, but as you directed i created the database and afters directly imported your given tables.sql file in phpMyadmin, and filled the
db name which is cms, username and pass in config file.
i can’t get about the admin username&pass, does it same as that of db or do i have to create one?
secondly, i get this error “Sorry, a problem occurred. Please try later.”
pl advise me on this, as i always was looking for second option for wp. great stuff, thanks for availing it free.
Thanks
Look in config.php the default admin user and password is in there, and is NOT the same as DB user and password.
Hello,
Thanks for your great article.
I’ve a really strange problem. When I create a new article and set its date to be 2012-06-18, it will be saved as 2012-06-17 and each time there is a date in the box, after saving, the date is 1 day before it !!!
I can not figure out how to fix it. Thanks for your help. I really appreciate it 🙂
@philatnotable: Thanks for the suggestion – I’ll add a tutorial on PHP exceptions to the schedule.
@Antonio82: PDO parameter binding doesn’t work with ORDER BY clauses.
@Sepehr: Sounds like you have a time zone mismatch between your MySQL server and your PHP script. Did you set the correct server time zone in your config.php?
Hello All…!
Anyone knows how to modify this great CMS to edit “time” in “publicationDate”…to save and to edit…?
I only got 00:00:00 time on my database…! I wish to edit this…!
I have some probs using “mktime” in “storeFormValues”…!
Many Thanks…!
Hi Matt, great tutorial! I’m just having a problem, I’m getting the error “try again later” it means some problem with the connection, I imported the database to my mysql database (wich means it’s not local) and I put the name and password so I wonder what could be going wrong, I know that you say on the tutorial that you have to also put the database name (I didn’t because with the mysql database you put the full location to find the database like “hostedresource…etc..etc), and in these cases I never had to put the db name.
I figured it out, I had to write the database name, now I want to ask you the best way to create a page for the user (admin) to register the username and password through a front-end (admin) page ’cause now, the admin username and password are set in the config code but if the person doesn’t know coding or doesn’t want to do that, how can they sign in? Thanks!
Hello Mr. Matt
First i would like to thank you for taking time to write these really helpful tutorials, i learned alot.
I merged all your PhP CMS scripts in one for my school project.
Now only thing i cant figure out is how to put some content on right next to my articles.
I highlighted the area i want to put some content with red color, so you can have idea what i want.
Here is the picture:
http://tinypic.com/r/3480lep/6
I would appreciate if you tell me step by step which .php and .css files i should change (note all .php files have original names that you made).
Thanks in advance.
@chotikarn I implemented the pagination code you provided and I think I implemented it correctly but for some reason when I click on the links (1, 2, Next…etc) the page doesn’t show any articles. And then when I click Previous, that page doesn’t show any articles either. I tried it using the original code from this site too but the same thing happens.
Would you or anyone here have any idea what I can do to get it working? Thanks.
@Marki: Use date() to format the date for the text field in the form, and explode() / mktime() to parse the date entered in the text field and convert it back to a timestamp.
@eddie: I don’t understand your question totally. You need to start with a username/password at some point, and the easiest way is to hard-code them into config.php. The alternative would be to create some sort of default password (a potential security hole) and redirect the admin to a page on first login where they could reset their password.
@Dug: I’m not sure what you mean by “content” here. Static content? Put it in the viewArticle.php template.
@DOC: I might write a pagination tutorial if there’s enough demand…
Thanks for your good tutorials!
I also have a question.If I wanna post articles in Chinese by using the simple cms,how do I need to modify?
Can someone help me out on adding 2 radio buttons with 2 different sizes for thumbnails? Instead of the constant one in i config.php.
I would also like to change the language of the months in the dates, any ideas on how to do this?
Thanks in advance!
@hd_199053: If you need to use Chinese characters then make sure you’re using Unicode (UTF-8) throughout the whole process, from the HTML page encoding, through to any PHP string functions such as preg_replace() and, finally, the MySQL table encodings.
eg see the ‘u’ modifier at http://php.net/manual/en/reference.pcre.pattern.modifiers.php
This page should get you started: http://malevolent.com/weblog/archive/2007/03/12/unicode-utf8-php-mysql/
@srtu: You mean radio buttons for the administrator to choose thumbnail sizes, or for the user? More details needed please.
Dates: Use http://www.php.net/manual/en/function.setlocale.php to set your locale, then use http://www.php.net/manual/en/function.strftime.php to output the dates instead of date().
@matt
Thats correct. Using radio buttons for the administrator.
Was looking at set locale before but I didnt seem to make it work with Swedish, maybe I should just do a array for it?
Very useful and informative.
Thank you Matt
Hello there, i get this error please can anyone help me?
Warning: mysql_real_escape_string() [function.mysql-real-escape-string]: Access denied for user ‘root’@’localhost’ (using password: NO) in /home/u972373064/public_html/blog/classes/Article.php on line 105
Warning: mysql_real_escape_string() [function.mysql-real-escape-string]: A link to the server could not be established in /home/u972373064/public_html/blog/classes/Article.php on line 105
why does it says for user root@localhost?
i am running in a public mysql server with username and password both defined in config.php
Hi Matt, thanks for the brilliant tutorial! Very useful. I have a question though. On the homepage where it displays all of the articles, I have placed a search box (just a textbox within <form> tags and a submit button). This allows users to search for articles using the title. Im a little stuck on how I can perform the search using your current structure as I would like the results to display on screen as normal articles like on the homepage but filtered. Hope you or someone can help. Thanks
@jj007: I would modify the homepage() function in index.php to check for a ‘searchQuery’ parameter (or whatever your search field’s called). If it exists and is non-empty, pass it as a third argument to Article::getList().
Then modify Article::getList() to check for the third parameter; if present, use it to add a WHERE clause to the SELECT statement that filters the returned articles to just those whose title contains the value of searchQuery.
What is the best way to perform good SEO on this setup? I have an index page which sends me to the home.php page which has information on including word through out the text that relates to metadata. On this page i also include the php header which contains a lot of my meta data yet it doesn’t seem to work for google. Either having index.php to home.php doesn’t work very well for SEO or including the header, has anyone managed to get it to be successful?
Hi Matt, Thanks a bunch for this cms, it looks awesome.
However I have not been able to get mine set up and working…
I have uploaded it to my website, I have created the database as follows, put my correct password, username etc on the config.php file as well as the correct time. And uploaded..
However I only get the error message
‘Sorry, a problem occurred. Please try later..’
Here is the code for config.php – wonder if you can help at all?
(I have put the dbname and username in question marks for security reasons)
Thanks, look forwards to hearing back.
Hello everyone! Thanks for this great tutorial!
I am trying to introduce clean urls but I can’t do it…
I have my .htaccess exactly like this:
I then refresh the main page (of localhost), and click an article.
The url stays the same (http://localhost/test/?action=viewArticle&articleId=1) why is this???
THANKS IN ADVANCE! THIS IS GREAT!
Ok, now I have managed to get to the article if inputting the adress manually (http://localhost/test/articles/1), shouldn’t it redirect me automatically to this adress when clicking an article?
This is the code in my htaccess:
And it keeps giving me problems because now, it’s just a blank page without any images, where images should be there’s an error (image not avaiable) because the the server is trying to acess the images in the following folder: (http://localhost/test/articles/images/logo.jpg)
Can someone please copy/paste the correct .htaccess code and homepage.php code for auto redirect to clean urls?
THANKS IN ADVANCE!
can i use this code in creating professional cms? because i am new to php. thanks,
Im having the same problem than avedus
Warning: mysql_real_escape_string(): in D:xampphtdocscmsclassesArticle.php on line 105
Warning: mysql_real_escape_string(): A link to the server could not be established in D:xampphtdocscmsclassesArticle.php on line 105
A few weeks ago it was working as a charm, but now I’m getting this error, it’s while trying to get the total rows of article(s)
[Edited by firefly2024 on 20-Nov-12 05:47]
@firefly2024: Presumably you replaced the mysql_escape_string() call in the original tutorial with mysql_real_escape_string(), and either the link identifier you passed is invalid, or you didn’t pass one and PHP can’t connect to your MySQL DB using the default settings. Read more here:
http://www.php.net/manual/en/function.mysql-real-escape-string.php
Either make a connection yourself and pass a valid link identifier, or make sure your default MySQL connection parameters are correct, or stick with the original mysql_escape_string().
Hi everyone , do you know in that script where i can put mysql_query(“set character_set_database=’utf8′”);
mysql_query(“set names utf8”);
@Geraki: See http://www.laszlo.nu/post/34159352/how-to-use-utf-8-with-mysql-and-php-data-objects-pdo
You shouldn’t call “set character_set_database=’utf8′” manually at all – see: http://dev.mysql.com/doc/refman/5.0/en/server-system-variables.html#sysvar_character_set_database
Just make sure you create your tables using the utf8_unicode_ci collation.
Hi Matt, great and helpful tut! Thanks for your expertise. I am wanting to play with the homepage and am wondering if it’s possible to put the articles Table in an XML or JSON file, and then link data to an RSS feed to track new articles added. Is this possible? If you can provide an example and/or explanation of XML/JSON within the context of this tutorioal it would be very helpful to a lot of us.
[Edited by Jim22150 on 03-Jan-13 12:09]
@matt I was wondering how editArticle.php validates itself so it isn’t submitted blank? because I can’t seem to find any code for it?
@mikewkd2: What makes you think it does any validation?
I forgot about the existence the “required” tag in the inputs
I thought it was validating because I couldn’t submit the form blank or with missing field
@matt I have used your tutorial a couple of times for different uses now and its great, However on this occasion im in need of help which im sure is dead simple im just having a dead brain moment, How do i insert a field (Couple of fields in the form) to an array, im unsure whether to change the form setup or the insert value in the Article. Nay help or guidance will be great.
Ian
HI all!
First off I just wanted to say a HUGE THANKS to Matt for posting this very helpful article 🙂
I have spent the better part of 2012 up to the present, expanding on this CMS framework. I have now created a github project for others to share in the development from here forward if anyone is interested: https://github.com/geraldbullard/gnscms
I have integrated the Charisma Fully Responsive Open Source Admin, a .simplesite Responsive theme for the front end and have recently started working on the menu system functionality…
The installer is not 100% complete but is there in the admin for the database schema.
Also I would love to have anyone work on pagination for the pages/settings listings in the admin and/or front end.
Again this system is FAR FROM COMPLETE and needs a good many small iterations to be widely acceptable as a stable release for any production sites, but is nonetheless fully capable of supporting live web sites with a little TLC 🙂
I hope you all enjoy what I have created from Matt’s gracious contribution and please send those pull requests to add to this growing system!
======================================
NOTE: you will NOT recognize anything about the look of the admin or front end, only when you get into the class and layout areas will anything looks similar.
[Edited by geraldbullard on 04-Mar-13 16:31]
geraldbullard, thanks you for share this. I gonna test your CMS soon as possible.
I was work around with matt’s CMS too, and you give me other opportunities to improve my PHP skill.
Thanks.
Make sure to get the fresh zip from github tonight, I actually updated the installer and added a “show in menu” feature plus had to work on the 3 included templates on some overlooked issues…
just get the latest zip, from the development branch: https://github.com/geraldbullard/gnscms/tree/develop and upload to your site, then just hit the location in your browser and it should redirect you to the installation. Also one very important note…
you will have to update your .htaccess line from
RewriteBase /afternooncms/
to
RewriteBase /yourfoldername/ or the mod_rewrite will not work on the urls 🙂
if you are installing to the site root then that line should be
RewriteBase /
best of luck 🙂
[Edited by geraldbullard on 04-Mar-13 21:35]
I have an Incredibly odd bug I was hoping you could explain.
Every time I save or update an article the publication date ends up subtracting one day from whatever the specified publication date is. For example: Publication date is listed as 2013-03-05 and once saved it will be shown as Mar 4 2013, now if go back and edit the article then hit save it will automatically subtract another day and be displayed as Mar 03 2013.
Any idea where this could be happening? I had used the default source code and only made small modifications to get it working on our web host and everything else but this odd bug works wonderfully.
Thank You
Im having issues dealing with special characters (in this instance the ‘&’ character) in the title and summary fields of editArticle form. I am being returned blanks wherever they are used.
I pass content data through ckeditor for the content field and all charcters works fine there.
I have changed all pages to UTF-8 charset and my database also uses UTF-8, so now im not sure where the problem lies.
Any tips or solutions would be welcomed.
[Edited by andy_baz on 14-Mar-13 10:04]
@andy_baz
Check the ‘public function __construct( $data=array() )’ in the article class and take a look at ‘ preg_replace ( “/[^.,-_'”@?!:$ a-zA-Z0-9()]/”, “”, $data[‘title’] ) ‘.
Matt has set the function to escape characters that could be used with malicious intent, read section ‘2. The constructor’ to see if you want to bypass this safety step.
I’ve just been using characters that aren’t being replaced; like using ‘and’ instead of ‘&’.
Cheers
I downloaded you files for the CMS but I have a database started already that is called events instead of articles. It also has more events. I am having issues getting the code edited to work with my databases. Here is the table.sql code so you can see my database. Please help! 🙂 hotmail is rhonda8181
— phpMyAdmin SQL Dump
— version 3.5.1
— http://www.phpmyadmin.net
—
— Host: localhost
— Generation Time: Apr 23, 2013 at 12:40 AM
— Server version: 5.5.24-log
— PHP Version: 5.3.13
SET SQL_MODE=”NO_AUTO_VALUE_ON_ZERO”;
SET time_zone = “+00:00”;
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!40101 SET NAMES utf8 */;
—
— Database: `inclasscms`
—
— ——————————————————–
—
— Table structure for table `event`
—
CREATE TABLE IF NOT EXISTS `event` (
`event_id` int(25) NOT NULL AUTO_INCREMENT,
`event_title` varchar(25) NOT NULL,
`event_location` varchar(25) NOT NULL,
`event_date` date NOT NULL,
`event_posted_date` date NOT NULL,
`event_cost` decimal(10,0) NOT NULL,
`event_contact` varchar(25) NOT NULL,
`event_contact_email` varchar(25) NOT NULL,
`event_description` text NOT NULL,
PRIMARY KEY (`event_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=5 ;
—
— Dumping data for table `event`
—
INSERT INTO `event` (`event_id`, `event_title`, `event_location`, `event_date`, `event_posted_date`, `event_cost`, `event_contact`, `event_contact_email`, `event_description`) VALUES
(1, ‘smithWedding’, ‘johnston’, ‘2013-04-20’, ‘2013-03-20’, ‘20000’, ‘rhonda’, ‘rhondasmith@hotmail.com’, ‘Rush wedding’),
(2, ‘viengGraduation’, ‘desMoines’, ‘2013-04-24’, ‘2013-01-01’, ‘15000’, ‘kim’, ‘kimVieng’, ‘Asian event’),
(3, ‘briadalShower’, ‘grimes’, ‘2013-05-08’, ‘2013-03-13’, ‘10000’, ‘sarah’, ‘sarahh@gmail.com’, ‘conservative bridal shower’),
(4, ‘retirement’, ‘urbandale’, ‘2013-04-12’, ‘2013-03-12’, ‘5000’, ‘harry’, ‘harry@gmail.com’, ‘suprise’);
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
I would like to know how you would write this for multiple tables
I am getting this on the index.php page.
“Sorry, a problem occurred. Please try later.”
Then I downloaded the source code and again I got the same error.
Can you please help me out here.
I am using LAMP.
Thanks
Hi again all, I have been going thru MANY MANY updates and converted the development branch to the “master” branch. https://github.com/geraldbullard/gnscms/archive/master.zip
for all who are interested in the gnscms please download from the master branch from now on 🙂 and post any issues to the “Issues” page for gnscms ( https://github.com/geraldbullard/gnscms/issues/new ), if not directly related to the original code for “cms in an afternoon” 🙂
This article is one of the worst I have ever seen…ever! I am not just saying that, check out the demo versus the download code for admin.php. Its reidiculous, and no ideas how to change passwords or username in admin.php, for beginners? rubbish!
Will someone ever post a real simple “How create a simple CMS” article. albeit she did mention that people are using different servers, have to give her that, but how to configure this monolith step by step she didnt include.
Hmmm, lets see…. if I were to give away free food to hungry people, do you think they ( idiot_asleep ) would complain that it didn’t meet their taste expectations?
Yet the free code this article provides could be considered one and the same to “hungry” developers seeking more knowledge and skill. not to mention the time involved in not only writing the code, but documenting the method to recreate a system for one’s own needs… gnsCMS for one.
Sorry to reply with what may seem to be a personal attack, but it simply gripes me to see ANYONE so easily disrespect the generosity of others in an effort to assist those of less skill and knowledge and give of their time so freely.
And for the record this article was not intended to be a FULL explanation of how to develop and implement an all encompassing CMS system, merely a very simple base to build upon.
WERD!
[Edited by geraldbullard on 23-Jun-13 22:45]
I completely agree. This is the best and most helpful of all the tutorials I have found online. The code is a great starting point to a great CMS. The tutorial is well produced.
Hi, great tutorial.
Unfortunately after completing it though I can’t seem to get the system to load properly. I copy-pasted my own code from the site and also downloaded the code with the same results.
Using Firefox/iceweasal to go to http://localhost/cms just displays a small section of index.php –
while Chromium just displays the entire content of index.php
I feel like there must just be some simple step I am forgetting, but I don’t know what it is. Do I have something configured wrong with the LAMP server?
SOLVED —- I JUST WENT BACK THROUGH THE DEBIAN LAMP SETUP STEPS AND IT SOLVED IT. THANKS!
[Edited by ross on 07-Jul-13 19:42]
Please, heeeeeeeelp!
I’ve tested locally with Mamp… Works well
But when you upload it to a server outside, it doesn’t work at all… Is not anything with the database, because it connects, but it seems that lost connection or something, because it simply doesn´t fetch data from the database, I tested with the original source code and nothing.
Please.
Hello there!
I have adjusted a few settings, instead of Article class , I have chaged it to House and houses.
Now : Editing works fine, and the content gets updated, but adding new content does not work, I enter all the information, get the Message that my changes have been saved, but nothing get added.
Any idea what it could be?
Kind regards,
Dom
[Edited by DisturbedGoW on 02-Aug-13 05:47]
Thanks for all the kind words on this tutorial – I’m really happy that it is helping so many people. 🙂
@Ngelltran and @DisturbedGoW: Did you look in your server error log to see if there’s a database exception in there?
Matt
Hi,accomplishments for the job, clearexplanation.I installed the cms easly.Can I add a dynamic menu with Articles?
I would like to add menu items that link to articles.
Best regards,
Roberto
Hello All…!
It was working fine to me until i change WAMP to a new version. Dates became wrong showing “31 DEC 1969” on all posts.
Database shows me correct dates, but on HomePage and AdministrationPage shows me incorrect dates (31 DEC 1969).
I didnt change anything in the code, only changed WAMP version.
Could you help me?
Thank You.
P.S.: My DB has 2 diferent dates on same table: publishingDate and closingDate and only one has the problem. Below i show where i believe is the problem:
public function 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, $m, $d, $y );
}
}
if ( isset($params[‘closingDate’]) ) {
$closingDate = explode ( ‘-‘, $params[‘closingDate’] );
if ( count($closingDate) == 3 ) {
list ( $y, $m, $d ) = $closingDate;
$this->closingDate = mktime ( 0, 0, 0, $m, $d, $y );
}
}
}
[Edited by Marki on 02-Sep-13 23:40]
Hello
Can someone explain to me how the code handles the control of the form. When you click on the button and you did not complete the fields as for example, the field is red and indicates. I’m french and it must be the browser that runs because the error is in french and said Please complete the fields.
I searched but did not find any function that
Thank you in advance
I found …
It should simply add the required input:
<input type=”date” name=”myDate” title=”Date” value=” “required>
Works with every browser except safari
Please help. I’m using MAMP. When I go to my localhost, select cms I get a blank screen. Can anyone help me with whatever I did wrong.
And thank you for the tutorial. It was wonderful.
Hello,
I only whant to say this is a Great article, its workin fine.
Greetings
Hello, congratulations for the article.
How can I integrate pagination in PHP in the article list ?
Thanks.
Hi All,
i have 2 dates in the same table, how can i manage “storeFormValues in class Article” to work with this 2 dates?
publicationDate
closingDate
Thanks.
———————————–
Resolved my problem adding UNIX_TIMESTAMP(closingDate) statement at function getList in Article class.
[Edited by Marki on 22-Nov-13 10:15]
This article is very helpful at all, I am as new to learn web programming very helpful at all. Thank you very much ..
Hello… Hopefully this isn’t too late.
I have done the entire article, the add new article works on my server, and is saving the article data to the database, but none of the articles are showing up either in the list on the admin side, nor on the homepage.
I’m not sure what I missed, or if anyone has had this issue, but it seems to be the only part of this script that doesn’t work for me.
Anyone with any idea what I missed?
Thanks
Interesting post! I have a problem when typing in cyrillic – it does not insert any data in the table, or inserts only numbers instead of letters. I added <meta charset=utf-8″> in header.php but no result! Could you help me?
Also it would be great if there is a possibility to add or remove images in the posts 😉
Thank you in advance!
Best Regards, me 🙂
Hi,
I found this article very helpful and I have managed to build website based on 80% on it, but my problem is in servers that are not supporting PDO.
Is there any way to rewrite this code and use it without PDO?
Thanks in advance.
First of all great tutorial! thanks so much.
@matt – are you stilll planing to make a pagination tutorial? It would be the greatest.
@chotikarn – I was trying to implement your code for pagination, but i get some problems about some undefined index and variables, do you maybe have time to help me with it?
[Edited by legarth on 15-Dec-13 17:54]
Hello All!
Awesome tutorial, extremely approachable and informative!
I am trying to develop little site, wchic is non-english. Could you please help me on how to change publication date from being displayed like “Published on 11 January 2014” to “Published on 11-01-2014”?
Thanks a lot!
All the best in the New Year!
Thanks for this wonderful tutorial but i’ve been trying to implement pagination in the archive.php and listarticles.php but i’ve not been able to acheive this….pls can you write a follow up tutorial on pagination or can anyone help…..Thanks
I put the code from the homepage.php that shows the last 5 articles in to a section_footer.php include file.
When I click on the link to view the article it takes me to the viewarticle.php but I get a “undefined index” message in the include section footer.
When I go to the article archives it doesn’t do this.
Any ideas how to correct this would be helpful.
Thanks
I enjoyed the tutorials it work good!! I have a question…
If i want to duplicate the edit form for another similar usage for example a slideshow with articles in the same homepage what is the better way ??
@smartin1970
problem when you want to add new article
open Article.php
find $conn = new PDO( DB_DSN, DB_USERNAME, DB_PASSWORD );
replace $conn = new PDO( DB_DSN, DB_USER_NAME, DB_PASSWORD );
@malpikrol
open listArticles.php
find
<?php echo date(‘j M Y’, $article->publicationDate)?>
replace
<?php echo date(‘d-m-Y’, $article->publicationDate)?>
[Edited by pedja82 on 12-Feb-14 08:40]
Hi,
Im hoping someone can point me in the right direction for this. I am having a few difficulties moving around the index.php file.
I basically wanted the index.php file to become a news page on my site but i dont want the user to see in the browser URL that it is aimed in the cms/ directory.
So i moved the file out and got countless errors so i moved everything out(not ideal), in to the root and it works but when u click on an article it redirects back to the home page and the archive link on the index.php page.
Is there a reason for this or a better solution?
A few of us sees this:
“Sorry, a problem occurred. Please try later.”
What kind of an error-message is this???
The only purpose of such a message is to obscure the cause of what’s creating the error-message. The fact is, no one will ever be able to correct any fault occurring with their scripts or the server configuration.
One other thing: “Please try again later.” -Is this a joke? If your car runs out of gas,-do you seriously think it helps to try again later without filling gas?
Here’s the solution:
Open up config.php in any text editor and remove the following at the end of the script:
Save config.php.
Now, refresh your browser window and look at the error message. If it says anything about mysql and username/password, you need to edit config.php and type in the correct database name, username and password. Save config.php and refresh the browser window. Now, everything will be OK,-or you’ll get another error message that contains something with “Fatal error . . PDO blah-blah-blah in some document at line number so and so . . . “
If this happens you need to uncomment a couple of extensions inside the php.ini-file, namely:
extension=php_pdo.dll and extension=php_pdo_mysql.dll
If there’s a semicolon in front of any of these, the required modules to make PDO work will not be loaded, so remove the semicolons and restart your server. Refresh browser window. If you still get the same error message,-stop apache and then start apache again instead of just restarting. As an alternative you can reboot your computer.
Make sure you are editing the php.ini-file that the system is actually reading. You can make a phpinfo.php-file and run it in your browser to see where your php.ini resides and also which PDO modules are loaded. If you have a mysql-database, mysql should be listed under the PDO-section.
A few of us sees this:
“Sorry, a problem occurred. Please try later.”
You are free to change the error messages to whatever you want.
But you seem to have missed the point of the article and TUTORIAL.
It is NOT for you to use as is. It is, as it says, a tutorial, so anyone can inspect the code and LEARN the programming necessary and how to handle errors for themselves.
If you want to change the language of the interface …. You can.
If you want to extend the functionality of it ….. You can.
And if you ARE using it on a production server be aware that sending detailed error messages WILL assist vandals and ‘crackers’ in finding what vulnerabilities may exist.
[Edited by chrishirst on 22-Mar-14 14:34]
Dear Matt,
This tutorial is very helpful for me to learn PHP. I was looking for a tutorial to learn to make my own CMS. I have basic knowledge of PHP but I am learning more from your tutorial. Thanks a lot. I typed all your codes and followed your tutorial step by step. Everything is working fine except the following code:
public static function getList($numRows = 1000000, $order = “publicationDate DESC”)
{
$conn = new PDO(DB_DSN, DB_USERNAME, DB_PASSWORD);
$sql = “SELECT SQL_CALC_FOUND_ROWS *, UNIX_TIMESTAMP(publicationDate) AS publicationDate FROM articles ORDER BY ” . $order . ” 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;
echo $article->id;
}
$sql = “SELECT FOUND_ROWS() AS totalRows”;
$totalRows = $conn->query($sql)->fetch();
$conn = null;
return (array(“results”=>$list, “totalRows”=>$totalRows[0]));
}
i tried to click the title of the article and view the article but it doesn’t take me anywhere. The URL i get is: http://localhost:122/cms/index.php?action=viewArticle&articleId=
I tried to find what is wrong in the codes and downloaded your whole code and run it. The problem is the same. I tried to go through the codes and tried to echo variables. In the code above i is not returning id of the article. Help pls
I know HTML, CSS3 and how to set up and control tables in MYSQL using PHPMyadmin and the very basics of PHP but haven’t quite learned how to connect MYSQL with PHP.
This looks like a good informative tutorial and it will hopefully take me to the next step in making websites.
Btw, is it really a good idéa to have admin.php and config.php in the root directory?
[Edited by pennyc on 11-Apr-14 01:58]
php files cannot be ‘read’ from a HTTP:// request unless the values are written to the output stream using echo() or print()
Pagination !
Has anyone successfully done this that can assist me?
if not, Hi Matt,
Pagination seems to be a wanted thing around here people want and I have been trying to get it working on my site for quite some time without any luck can you please create a tutorial for integrating this in to this CMS.
I have tried Chokitarns example but i get quite a few errors and had no luck fixing them.
any help is much appreciated as i need this working before i can go live.
Many Thanks,
Martin
Is it just me or is the Form for article missing? I’ve gone through the entire code and can’t figure out how to create a new article? Can’t find any Form for it anywhere?
Hi, are you sure this works correctly?
if ( !isset($_GET[“articleId”]) || !$_GET[“articleId”] ) {
homepage();
return;
}
when i write non-existing id into url, it shows me an error instead of homepage.
thanks a lot.
That code does not check if an ID is valid and then deliver the appropriate article, it only checks if the key and A value is in the form associative array, and if either POST or GET is true it calls the homepage() function and THAT will serve the article … IF it exists, …. If it doesn’t, ….. you get a HTTP 404 error.
This setup works great. All i did was open ‘config.php’ and revise the DB_USERNAME and DB_PASSWORD. If you are using a localhost setup (XAMPP or WAMP) just revise DB_USERNAME to “root” and DB_PASSWORD to “” (unless you initiated a password.
If your CMS is accessible from the outside world ie; The Internet. Absolutely do NOT, EVER use the root user and password for database communication.
The root user has ALL privileges allowed so if anyone does try cracking your system they can delete everything.
Many thanks for this tutorial. I suspect it might take me more than an afternoon, especially as I plan to convert it to use SQLite rather than MySQL.
PLEASE BE AWARE
A site i created using this CMS has been hacked this week and had the homepage removed and replaced with this php file…
<html>
<head>
<title>Fuck You</title>
</head>
<body>
<br><h>HAJO LEFKAR SIIIIIIDIIII…chickh mohamed el anka..<h>
</body>
</html>
Has anyone else had the same problem….??????
Many websites do, and some that are not running ANY content management system.
I’m going to assume that your site is running on a server that uses cPanel for hosting management, and tell you that it is a long-standing flaw in the cPanel ‘legacy’ file manager that allows attackers to upload and run scripts that inject code into the commonly used “index” file names that your server uses.
You may find that there are some extra files and folders in the document root where the names start with a ‘.’ and/or have “shell” as part of the name.
How can i add a menu to this?? thank you
For what and where?
For your tutorial ( http://www.elated.com/res/File/articles/development/php/cms-in-an-afternoon-php-mysql/demo/ )
I want to be able to add a top menu, and have more pages, like, About Me, Contact, etc.
I am trying to learn php and mysql. I am a beginner in web programming and I am trying to learn. Thank you mate.
Hi,
I want to add checkbox ( if is checked, article will show on the page and if is unchecked, article will not show on the page). I modified Article.php and if I save unchecked checkbox, it save to database 0(maybe nothing, because I have default value 0), if I save checked checkbox, it save 1, but when I want change(update) article and save unchecked checkbox, in database is still 1. Can anyone help me with it ? I need to know where and what I have to change.
Will you be showing us the code that doesn’t work?
I put this to editArticle.php
And modify Article class –
But I don´t know what can I do to save 0 into database if it is unchecked. I´m beginner.
‘Unchecked’ checkboxes do not appear in the POST array so you cannot actually test for it having a value, so you have to test for it existing in the $_POST array.
this is pseudo code
And if it doesn’t … set the value you want in the database.
[Edited by chrishirst on 18-Jan-15 11:17]
Hi matt,
thanks for great tutorial
I have a problem and I hope you could help me:
I’ve made my own commenting system on your CMS but it’s not working. when I try to add a comment 500 error occurs. I think there is a programming error with it.
this is what I did:
1st: made a Comment.php in classes with this code:
then modified the index.php like this:
and in viewArticle.php I also added:
Check the site error logs for what the error is, “a 500 status” covers a LOT of possibilities.
Hi, I have just a question.
What mean 100000 in index.php ?
It´s in function archive ->
It´s for numRows isn´t ?
I need to change select in public static function getList to display articles with active=1 ->
It´s works in homepage but not in category. If I add this condition, archive doesn´t show any article.
This is code for homepage->
Hi
I would like the articles to list horizontally next to one another on the homepage with their respective images rather than vertically under one another. Would this be possible? if so how must i edit the code code to achieve this?
Put float: left on the title link container and set it to a fixed width.
Hi, I’ve tried following the article but without using the login details aspect, however I only get the “Sorry, a problem occurred. Please try later.” message. Is there something else I need to add instead of the login???
A session cookie that holds the data that would be indicative that the user is logged in.
[Edited by chrishirst on 25-Mar-15 10:48]