Content M anagement System 293
Chapter 11: Content M anagement System 293
where s.story_id = m.story_id and m.author_id = a.author_id and a.author = ‘Jay Greenspan’
The next thing to be aware of is the relationship between the stories table and the story_versions table. As we already mentioned, versioning is very important to
a content-management system. In this case, it means that you must have access to old versions of articles. The way this schema is set up, the most current version of an article is always kept in the stories table. Additionally, every version of a story, including the most recent, is kept in the story_versions table.
Now on to the tables that define the stages in the editorial process and the users who will have access to those stages: content_users, content_stages, and user_stage_ map. Once again, a many-to-many relationship ensures that the application will track the users and stages and the intersections of the two easily enough. Want to find all the users that have the rights to make content publicly available? This will work:
select c.user_id from content_users c, user_stage_map m, content_stages s where s.stage=’Live’ and
s.stage_id = m.stage_id and m.user_id = c.user_id
This setup enforces some of the security needed in this application. If a user does not have a listing in the user_stage_map for a particular item, he will not be able to perform that task.
You might be wondering who has the rights to grant these privileges. Those peo- ple are listed in the content_admin table. If you decide to tweak this application for your own purposes, you may find that using these tables may be all the security you need. If your users don’t have access to the Unix box storing the database server, these tables should be enough. However, if your users are able to get at the data in others ways —perhaps by log- ging into the server and launching the MySQL command line client and running queries directly —you may need a bit more.
In a case such as this, you want to grant users privileges to log into the database. So you have to give them usernames and passwords using the grant statement dis- cussed in Appendix D. Then no matter where the users are accessing the data from they will only have access to the appropriate data.
Sounds great, right? Well, it would be great, but when you try to do this your application runs into some of the limitations of MySQL, and working around these limitations makes for some weird solutions.
As of the writing of this book, MySQL is missing two things you could have made great use of here. First is a feature known as Views. A view is pretty easy concept to understand. When creating a view, an administrator defines a virtual table that may be a join of many tables and may only show some of the columns in
294 Part IV: Not So Simple Applications
the used tables. By restricting the user to a view of the data, the administrator can restrict what the user is permitted to see. Note that in most SQL servers, views are read only.
Tip There isn’t a development tool on the planet that doesn’t have its quirks. Every language and every database presents it own challenges.The more of these that you are aware of before you start writing your application, the better off you will be.
The second thing missing from MySQL that would have been nice to use here is
a more restrictive grant statement (please see Appendix D). As it stands, MySQL can grant authorities on several levels: for an entire installation, for a specific database, for tables within a database, or for columns within a table. While this may sound quite extensive, it is really not as complete as it could be.
Consider this problem: in MySQL, using table- or column-level grants, how could you prevent user john, who needs to have only editorial privileges, from updating stories that are already live? The best way to go about it would be to have very specific privileges in the stories table. If the stage_id for Live is 4, you’d want
a grant to john that gave him access to alter any of the rows in the stories table, except those where stage_id = 4. Other databases allow this, but MySQL does not. The best you could do with MySQL is provide backup security to the content_ users, content_stages, and user_stage_map tables. This backup plan will only work within the PHP scripts that access the database. If you grant users permission, they will be able to log into the database via avenues other than the Web. And, as we already mentioned, the rights you can grant may not be as restrictive as you like. Grant rights at your own discretion.
Here’s how the secondary security works within the PHP scripts. When the administrator creates a stage, a row is added to the content_stages table. In addi- tion, a create query makes a table with a single column to store the story_ids. For the proofreading stage, there is a table called proofreading_stories.
When new users are created, rights to these tables will be granted when appropri- ate. As a story works its way through the editorial process, the story_id is written to the corresponding stage table, such as proofreading_stories. If the user does not have rights for that table, the update is rejected.
Here’s a quick example of how this would work. Say that you, the administrator of this content management system, decided that you needed to add another stage to your editorial process, called format_review. If you are logged into the applica- tion as a user listed in the content_admin table, you will have the rights to create this stage. The stage will first be added to the content_stages table. When you cre- ate the stage, you will indicate which of the users should have the authority to use this stage. Those users will be added to the user_stage_map table with a different row for each user_id/stage_id combination. This is our primary security, and if