<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>HirdWeb &#187; Code</title>
	<atom:link href="http://www.hirdweb.com/tag/code/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.hirdweb.com</link>
	<description>Another Blog clogging up the already crowded internet</description>
	<lastBuildDate>Wed, 28 Jul 2010 16:05:05 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0</generator>
		<item>
		<title>Resetting the passwords</title>
		<link>http://www.hirdweb.com/2008/10/27/resetting-the-passwords/</link>
		<comments>http://www.hirdweb.com/2008/10/27/resetting-the-passwords/#comments</comments>
		<pubDate>Mon, 27 Oct 2008 12:30:06 +0000</pubDate>
		<dc:creator>stephen</dc:creator>
				<category><![CDATA[Applications]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Code]]></category>

		<guid isPermaLink="false">http://www.hirdweb.com/?p=121</guid>
		<description><![CDATA[In some applications on the web, you are required to log in to view content, post content, or any other sort of thing. With this, there will be times when a member of the site/application/whatever will forget the password they used, and it will have to be reset for them. So there are different methods [...]]]></description>
			<content:encoded><![CDATA[<p>In some applications on the web, you are required to log in to view content, post content, or any other sort of thing. With this, there will be times when a member of the site/application/whatever will forget the password they used, and it will have to be reset for them. So there are different methods of doing this, and different ideas behind what should make this work. I am going to give you one that I use, which will use a close to random method for resetting the passwords. </p>
<p><span id="more-121"></span></p>
<p>First off, we need to discuss the pros and cons of storing passwords in plain text. Presumably, the passwords are stored in a table in the database. Are they stored plain text, or are they hashed? Does it matter? Maybe it does, maybe it does not. Some of the pros and cons of this are based on the way that the data is used. What does your site do, who looks at the table, what access level do other people in the department have? Does the password allow access to other areas of personal data that people should not have available? These are questions that would need to be answered in a case by case basis. On one project I worked on, it was a local non profit organization who had members from other businesses. Their profile contained only contact info for the members at their place of business. No personal info (ie SSN, credit card numbers, etc) were stored, and any transactions done went to the Pay Pal check out. They wanted the passwords to be emailed if they forgot, so storing the passwords in plain text were fine, and if the data got out, then all they would have is business info for the members. However, in another project, there was going to be personal info, including credit card  and transaction history. There would be a team of DBAs who would have access to the table, as well as a team of developers. Certain managers also had access. When the question of password storage came up, there was no question or debate, the passwords would be hashed. So answer this question on your own according to the project. </p>
<p>Second, now that we have answered that question, we need to answer the question of what to do when a user forgets their password. Reset it or send them an email with the password? If you are storing in plain text and an email with the password is what is wanted, then you can stop reading here. You now need to email that password. If not, or the password is hashed, then we need to reset the password. Now we get to the meat of the code that would do this. </p>
<p>*** As a note, do not forget to get business rules/requirements for what kicks this code off. Is just the email enough, or do they also need the username, and possibly a security question? Make sure that is defined to validate who is requesting the reset. </p>
<p>Now, in the function, or object or whatever to reset the password we need to do a couple of things:<br />
1. Find the account to reset<br />
2. Get a random password generated<br />
3. Store it in the table for later use</p>
<p>For the purpose of my long-windedness, and the focus of the code, the query on the table, the email being sent after the password is changed will not be posted here. </p>
<p>1. Finding the account is simple. Based on business rules, do a query to find the account that matches ALL the required input. If that is just username, then find that. If it is email address plus security question, match both items up. The query should return data you will need, like email address, username and/or full name (for personalization of the email), etc. I also request the current password, especially if it is hashed and the modified date (for the day it was last modified). </p>
<p>2. The new password can be based on anything. My random password is generated on a few things, all revolving around the current password and special characters. In this example, the password has been hashed and stored in the table. I am going to take this password, take a substring, and hash it using SHA1:</p>
<pre>
// Randomize a password based on the current one in three steps
// Take the current encrypted password, substring a random 10 chars, then SHA1 it
$temp1 = sha1(substr($r_user['Member']['password'], rand(1, 20), 10));
// Now get only 5 characters from this new string
$temp1 = substr($temp1, rand(1, 20), 5));
</pre>
<p>Since the hashed password is always going to be the same length, I am going to be safe with my random parameters. I want to grab only 10 characters from the original hashed password. This will give me some numbers and letters, with uppercase included, and I am going to take that string of characters, and hash it up with SHA1, then grab only a random 5 characters from that. The next step is to get some random special characters.</p>
<pre>
// Create a string of characters, then randomize to get 3 special characters
$string_spec = "!@#$%^&#038;*()_+"      //12 characters
$temp2 = substr($string_spec, rand(0, 11), 1) . substr($string_spec, rand(0, 11), 1) . substr($string_spec, rand(0, 11), 1);
</pre>
<p>So that will give me three random special characters. I then need to get the next portion of the reset:</p>
<pre>
// Take a random 5 chars from the encrypted temp1 string
$temp3 = substr($temp1, rand(1, 20), 5);
</pre>
<p>Much like the first temp variable, I am just doing the same, only I am taking a substring of the first temp, which was hashed. Now I get the modified day, based on a YYYY-MM-DD hh:mm:ss format. I am going to add up the Month and the Day, then Modulus (or remainder) divide those by 2 to see if it is an even or odd. I do this because I am going to put the special characters at the end of the string, or in the middle, dependent on the modify date. </p>
<pre>
// For this example $date = the value of the modify_date column in the table
$check = ( substr($date,5,2) ) + ( substr($date,8,2) );
if ( $check % 2 == 0 ) {
	// concatenate the strings with the special chars in the middle
	$reset_pass = $temp1 . $temp2 . $temp3;
} else {
	// concatenate the strings with the special chars at the end
	$reset_pass = $temp1 . $temp3 . $temp2;
}
</pre>
<p>Now one thing left to do, that is make sure the password is hashed going into the table, so that the user can log back in. </p>
<pre>
$new_pass = sha1($reset_pass);
</pre>
<p>3. Make sure that you UPDATE the table with the $new_pass and not the $reset_pass. We will send the $reset_pass to the end user. Also make sure to change the modify_date (if you have that field). Then send the email out upon successful UPDATE. </p>
<p>That is all I do. Seems like a lot, but it really is not. It is more of my explaining why I am doing things that makes it seem long. Will this work for everyone? Maybe not, but it is a step in making sure the new password is somewhat random, has numbers, uppercase and lowercase number, and special characters. </p>
<p>If you wanted to make this more secure, you could also add an expiration date to the reset pass, or check for last reset date, then fire off certain rules if the reset date is too close to the previous reset date. Things like that may help more, or could hurt. Remember that every application is different and what is best for the end user experience will dictate a lot of what goes in the requirements. </p>

<!-- Wordpress Connect Modules v1.05 -->]]></content:encoded>
			<wfw:commentRss>http://www.hirdweb.com/2008/10/27/resetting-the-passwords/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Ghost Town</title>
		<link>http://www.hirdweb.com/2008/09/18/ghost-town/</link>
		<comments>http://www.hirdweb.com/2008/09/18/ghost-town/#comments</comments>
		<pubDate>Thu, 18 Sep 2008 21:47:57 +0000</pubDate>
		<dc:creator>stephen</dc:creator>
				<category><![CDATA[Everything Else]]></category>
		<category><![CDATA[Code]]></category>

		<guid isPermaLink="false">http://www.hirdweb.com/?p=86</guid>
		<description><![CDATA[I did not post on Monday, which I really wanted to do. I am studying for the Zend Certification, but may have to put it off based on work load, and family obligations. Do I think I can just take the exam and pass it? Well, I am not that conceited, but I am sure [...]]]></description>
			<content:encoded><![CDATA[<p>I did not post on Monday, which I really wanted to do. I am studying for the Zend Certification, but may have to put it off based on work load, and family obligations. Do I think I can just take the exam and pass it? Well, I am not that conceited, but I am sure I may be able to pass it on a good day. However, test taking is not one of my strengths, so even if I knew everything on the test, I may still fail the test. So studying really helps me go through the exam work, and then helps me to get through the anxiety of tests.</p>
<p>And there is also new work things I am doing on the side. Most involve CakePHP, some involve just doing some very basic PHP work. So I am doing those and having less time to actually blog. And let&#8217;s not forget football season is now in full swing, so I spend a good portion of my Saturday afternoons watching college football and doing some studying.</p>
<p>Hopefully next week I can make a couple of posts, and hopefully I will make a couple of posts per week.</p>
<p>The next post will probably deal with more of the CakePHP work I am doing. (Working on a &#8220;social&#8221; calendar, like there isn&#8217;t already 2000 of them already).</p>

<!-- Wordpress Connect Modules v1.05 -->]]></content:encoded>
			<wfw:commentRss>http://www.hirdweb.com/2008/09/18/ghost-town/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Access Control Lists (ACLs) Part 3</title>
		<link>http://www.hirdweb.com/2008/08/27/access-control-lists-acls-part-3/</link>
		<comments>http://www.hirdweb.com/2008/08/27/access-control-lists-acls-part-3/#comments</comments>
		<pubDate>Wed, 27 Aug 2008 16:58:51 +0000</pubDate>
		<dc:creator>stephen</dc:creator>
				<category><![CDATA[Applications]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[ACL]]></category>
		<category><![CDATA[cakePHP]]></category>
		<category><![CDATA[Code]]></category>

		<guid isPermaLink="false">http://www.hirdweb.com/?p=72</guid>
		<description><![CDATA[In the first part, the idea and theory behind an ACL was discussed. In part 2, the set up of AROs, ACOs, and ACLs via the command line was shown. Now in part three, we look at why this is so important. Because an interactive site with memberships should never be static, what happens when [...]]]></description>
			<content:encoded><![CDATA[<p>In the first part, the idea and theory behind an ACL was discussed. In part 2, the set up of AROs, ACOs, and ACLs via the command line was shown. Now in part three, we look at why this is so important. Because an interactive site with memberships should never be static, what happens when a new member signs up? What happens when a member is promoted to an &#8220;admin&#8221; level? And what happens when users change? This can all be happened via ACLs. </p>
<p>In part 2, existing member were set up as AROs. And with user accounts, we also have to set those up as ACOs. Then those AROs (people) need to have permissions set for the CRUD actions. (Create, Read, Update, Delete). These actions are specific to the ACO, or object they are trying to manipulate. So if a user wants to edit their own account, do they have permission? If a user wants to delete another person&#8217;s account, do they have permissions to? With setting up ACLs, this can be checked. But what do we do when a new person signs up for an account? We need to create the code to do this. </p>
<p>In the Users Controller, we need to make sure we use the ACL component is included. So include this in the controller:</p>
<pre>
class UsersController extends AppController {
	var $name = 'Users';
	var $components = array('Acl');
</pre>
<p>Also remember that the Auth and Security components are also very powerful components and should be included as well, but the above only shows where to include the components. Now with this in place, we can no address the add (or register) function of the controller. </p>
<p><span id="more-72"></span><br />
When a new user registers an account on the site, we want to make sure to give them only access to their own account, and be able to read the other user profiles. The first thing is to create an &#8220;add&#8221; (or register, I actually prefer that because it just seems to be more logical to me, but I will use the &#8220;add&#8221; function for this example).</p>
<pre>
function add() {

}
</pre>
<p>Now we need to create the basics, or even better, better Bake up the views for the User controller. This helps set the base actions needed to add an account. But here is what some of the included actions should be:</p>
<pre>
function add() {
	if (!empty($this->data)) {
		// Sanitize the stuff
		$clean = new Sanitize();
		$clean->clean($this->data);

		// Set the data to the model
		$this->User->set($this->data);

		// Clean all of the elements in the data array, Attendee, Organization, and Bill information areas
		$this->data['User']['username']	  = $clean->paranoid($this->data['User']['username'], array('.', '-', '\''));
		// Make sure you clean all the user input values to help clean the input from the user, this is just an example line

		// Set any defaults for the user table, these would be items that are not on the form, ie avatar default, last_login date or ip, just to make sure there is no XSS on those fields

		$this->User->create();

		if ($this->User->save($this->data)) {
			$this->Session->setFlash(__('The User has been saved', true));
			$this->redirect(array('action'=>'index'));
		} else {
			$this->Session->setFlash(__('The User could not be saved. Please, try again.', true));
		}
	}
}
</pre>
<p>This is just some extensions of the Baked output from the Users controller. I always suggest to sanitze the data, and always set defaults if there are more fields in the table that do not have corresponding inputs. This just helps to cut down on XSS (cross site scripting) and helps to maintain some order of data expected to go in the tables. The next step is to add the ARO and ACO creations for this user. </p>
<p>Every user is an ARO, but they are also ACOs as they may have other users requesting to take action on their accounts. So we need to create the AROs and ACOs for the user right after the create() method:</p>
<pre>
. . .
$this->User->create();
if ($this->User->save($this->data)) {
	$usr = $this->User->getLastInsertID();
</pre>
<p>First we need to get the last inserted ID, because this is the user&#8217;s new user_id. We need to use that here. Then we need to instantiate the ARO object</p>
<pre>
$aro = new Aro();
</pre>
<p>With the ARO object ready to use, we need to create some date to send to the ARO. </p>
<pre>
$user = array(
	'alias' => $this->data['User']['username'],
	'parent_id' => 4, // member ARO
	'model' => 'User',
	'foreign_key' => $usr
);
</pre>
<p>We are creating the information we are to put in to the ARO, the alias (which is the username), the parent ID, in this case, the &#8220;Members&#8221; ARO is aro_id 4, (your parent_id may be different depending on how many AROs you have), the model, which is User in this example, and the foreign key which is the new user id that was just created. Now the Cookbook will say you do not need to put in the alias and the model/foreign_key. But I do because it makes the table easier to read, especially if you are looking at the table doing troubleshooting. It is easier for me, but feel free to find a good method for your own application. </p>
<p>Now take the data, create and ARO and save the data to it. </p>
<pre>
$aro->create();
$aro->save($user);
</pre>
<p>Creating the ACO is similar to the ARO, and this is how it would look. </p>
<pre>
$aco = new Aco();
$aco_usr = array(
	'alias' => $this->data['User']['username'],
	'parent_id' => 2, // User ACO id
	'model' => 'User',
	'foreign_key' => $usr
);

$aco->create();
$aco->save($aco_usr);
</pre>
<p>Now we have an ARO created, and an ACO, we need to make sure the ARO has certain permissions to the ACO (and its parent). Remember that a few rules for all new accounts is that they can only edit their own account, they can not delete any account, and they can view any account. So we can set these permissions after the ARO and ACO creations. </p>
<p>First we want to set it that they can only edit their own account. We are going to implicitly allow access to only this account. </p>
<pre>
$this->Acl->allow( array('model' => 'User', 'foreign_key' => $usr), $this->data['User']['username'], 'update' );
</pre>
<p>By setting the permission this way, it is only granting access to their own account in order to edit or update. If this ARO tries to update another account, it will not have the permissions needed to do so. Now we need to deny the delete action for all User ACOs. </p>
<pre>
$this->Acl->deny( array('model' => 'User', 'foreign_key' => $usr), 'Users', 'delete' );
</pre>
<p>This will deny all delete actions for this ARO. By specifying the &#8220;Users&#8221; ACO, we are safeguarding the delete action. This not only denies the delete action from happening on the &#8220;User&#8221; ACO itself, but all of its child nodes, or in other words, any ACO that has the &#8220;Users&#8221; ACO as it parent. Thus, this newly registered user can not delete any account in the system. </p>
<p>Here is it in its entirety:</p>
<pre>
function add() {
	if (!empty($this->data)) {
		// Sanitize the stuff
		$clean = new Sanitize();
		$clean->clean($this->data);

		// Set the data to the model
		$this->User->set($this->data);

		// Clean all of the elements in the data array, Attendee, Organization, and Bill information areas
		$this->data['User']['username']	  = $clean->paranoid($this->data['User']['username'], array('.', '-', '\''));
		// Make sure you clean all the user input values to help clean the input from the user, this is just an example line

		// Set any defaults for the user table, these would be items that are not on the form, ie avatar default, last_login date or ip, just to make sure there is no XSS on those fields

		$this->User->create();
		if ($this->User->save($this->data)) {
			$usr = $this->User->getLastInsertID();

			$aro = new Aro();
			$user = array(
				'alias' => $this->data['User']['username'],
				'parent_id' => 4, // member ARO
				'model' => 'User',
				'foreign_key' => $usr
			);

			$aro->create();
			$aro->save($user);

			/*****************************/
			$aco = new Aco();
			$aco_usr = array(
				'alias' => $this->data['User']['username'],
				'parent_id' => 2, // User ACO id
				'model' => 'User',
				'foreign_key' => $usr
			);

			$aco->create();
			$aco->save($aco_usr);

			// Set the permissions
			$this->Acl->allow( array('model' => 'User', 'foreign_key' => $usr), $this->data['User']['username'], 'update' );
			$this->Acl->deny( array('model' => 'User', 'foreign_key' => $usr), 'Users', 'delete' );

			$this->Session->setFlash(__('The User has been saved', true));
			$this->redirect(array('action'=>'index'));
		} else {
			$this->Session->setFlash(__('The User could not be saved. Please, try again.', true));
		}
	}
}
</pre>
<p>So that will set a new ARO and ACO for a new user. You would follow the same path for an event, or group, but you would only set a new ACO, and the permissions as needed, based on requirements. But this is not the only thing to do. We still need to check these permissions. As it stands right now, any user can edit or delete any other user, because we have not included the ACL check yet. So to demonstrate this check, we will use the Edit function as an example. </p>
<p>In the edit function, there is an ID passed to the function. This is the ID of the account to be edited. We need to check if the currently logged in user has the permissions to edit this account. We do that by doing an ACL check. </p>
<pre>
$this->Acl->check(array('model' => 'model_name', 'foreign_key' => "id of logged in person" "alias of ACO", "action requested");
</pre>
<p>So for this example, it is the User ACO we are wanting, more specifically the user account requested to be edited, and the action is (of course) update. So the first thing is to get the alias of the user to be edited</p>
<pre>
function edit($id = null) {
	$info = $this->User->read(null, $id);
}
</pre>
<p>This will pull the id into an array called &#8220;info&#8221; and we are looking for <i>$info['User']['username']</i>. Remember that your version may vary based upon the table info you have. Now we can do a check based on the currently logged in user, and in this example I am using the Auth component to get that. </p>
<pre>
if ( $this->Acl->check(array('model' => 'User', 'foreign_key' => $this->Auth->user('user_id')), $info['User']['username'], 'update') ) {
	// Do the edit stuff here
} else {
	$this->Session->setFlash(__('You are not allowed to edit this user.', true));
	$this->redirect(array('action'=>'index'));
}
</pre>
<p>This will check the currently logged in user to see if they have update permissions on the specified user_id&#8217;s ACO. If they do have permission, then it will go through the edit actions, checks, etc. If they do not, it bypasses that altogether and kicks them back to the index view with a message. </p>
<p>The same can be done for the delete action</p>
<pre>
function delete($id = null) {
	$info = $this->User->read(null, $id);

	if ( !$this->Acl->check(array('model' => 'User', 'foreign_key' => $this->Auth->user('user_id')), $info['User']['username'], 'delete') ) {
		// Do the delete stuff here
	} else {
		$this->Session->setFlash(__('You are not allowed to DELETE this user.', true));
		$this->redirect(array('action'=>'index'));
	}
}
</pre>
<p>Now this is just a simple example, and this same type of idea can be done for events, editing events, viewing events, etc. The same goes for groups and any other type of application where a permission check is needed. </p>
<p>Now, is my soap-box time. Why use ACLs at all? Wouldn&#8217;t a simple &#8220;level&#8221; table be enough to create this same type of effect? Yes and no. Remember that the right program for the job is determinant upon the job requirements. If an application is going to be used for a small purpose, and maybe you only will have 50 people at the most in a calendar application, then an ACL may be going a little overboard. However, if you have 50 people who are part of different groups, and based on group membership can do different things on the application, and the tasks may change from person to person based on work load, then an ACL may take some of the stress of of doing this type of thing. </p>
<p>Remember that an ACL is a great way to keep permissions in check with little human overhead involved. But sometimes the job requires that human overhead is needed, sometimes not. ACLs are great, and I use them frequently on big jobs. For the smaller jobs, I do not. But after this, hopefully you know better about what an ACL is, and how to use one in an application. </p>

<!-- Wordpress Connect Modules v1.05 -->]]></content:encoded>
			<wfw:commentRss>http://www.hirdweb.com/2008/08/27/access-control-lists-acls-part-3/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Queries using CakePHP find()</title>
		<link>http://www.hirdweb.com/2008/08/18/queries-using-cakephp-find/</link>
		<comments>http://www.hirdweb.com/2008/08/18/queries-using-cakephp-find/#comments</comments>
		<pubDate>Mon, 18 Aug 2008 17:51:09 +0000</pubDate>
		<dc:creator>stephen</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[cakePHP]]></category>
		<category><![CDATA[Code]]></category>
		<category><![CDATA[queries]]></category>

		<guid isPermaLink="false">http://www.hirdweb.com/?p=35</guid>
		<description><![CDATA[CakePHP now has deprecated some queries. The findALL, findCount, etc etc etc. This now uses the find() method for all of these, and has a basic syntax for this. If it is basic, why blog about it then? Good question. The documentation is there in the API, and is there in the Cookbook, it took [...]]]></description>
			<content:encoded><![CDATA[<p>CakePHP now has deprecated some queries. The findALL, findCount, etc etc etc. This now uses the find() method for all of these, and has a basic syntax for this. If it is basic, why blog about it then? Good question. The documentation is there in the <a href="http://api.cakephp.org/class_model.html#e60758f27fa8486a063b8cc424bad741">API</a>, and is there in the <a href="http://book.cakephp.org/view/73/retrieving-your-data">Cookbook</a>, it took me some time to really get a good idea on an applicable example and took many times of &#8220;trial and error&#8221; to help me get along. Because finding is good, and will give you all the information you need, if it is a simple, 1 table find. If you need to query two or three tables, how does this work. So this will go into those as well. </p>
<p>The basic idea of find, as listed by the API is this:</p>
<pre>
find(
	array $conditions,
	array $fields,
	string $order,
	int $recursive
);
</pre>
<p>This will find one record based on conditions, return the desired fields (or all of them if nothing is specified), order the results, and go so many levels deep (-1 for just the current table).<br />
<span id="more-35"></span></p>
<p>To get all the results instead of just one field, you would follow this:</p>
<pre>
find(
	string $notation_find,
	array(
		array $conditions,
		array $fields,
		string $order,
		int $recursive
	)
);
</pre>
<p>To find just one record, you need to use the first method, to find all records or a specific &#8220;notation&#8221; find, you would use the second method. The list of some of the &#8220;notations&#8221; are listed below:<br />
all<br />
neighbors<br />
list<br />
count<br />
threaded</p>
<p>So to use examples of this, lets say we have a &#8220;forum&#8221; area of a site, where it reads from a User table, a Forum table and a Post table. We have three tables, and we need to find certain things:</p>
<ol>
<li>The current Forum information (1 record, 1 table only)</li>
<li>The current number of posts in a forum (1 table, count)</li>
<li>The last post, and who posted it, in the selected forum (3 tables, 1 record, certain fields)</li>
<li>All posts in a forum topic, paginate results (3 tables, all records on specific conditions, certain fields)</li>
</ol>
<p>The way these tables (Forums, Posts and Users) relate to each other is by use of table-name_id (user_id, forum_id, post_id). User can have many posts, post belongs to a user, post belongs to a forum, forum has many posts. Now we need to do a simple query to get current forum info. I am doing this all in a forums_controller.php file. These can be a myriad of different function names, but each function would always be looking for some type of input. <em>NOTE: fields are arbitrary to this example. You can have as many or as little fields needed. </em></p>
<p>1. The current Forum information (1 record, 1 table only)</p>
<pre>
$forums = $this->Forum->find(
	array('Forum.forum_id' => $id),
	array('Forum.forum_id', 'Forum.forum_name', 'Forum.description', 'Forum.created'),
	null,
	-1
);
</pre>
<p>This grabs the current, or selected forum (passing in the $id from the function parameters), grabbing four fields from the table, no need to sort 1 record, and I only want this table&#8217;s data. This would return something like:</p>
<pre>
Array(
	[Forum] => Array(
		[forum_id] => 1
		[forum_name] => Sample Forum
		[description] => A Forum to discuss anything, upcoming and past.
		[created] => 2008-07-23 20:15:41
	)
)
</pre>
<p>2. The current number of posts in a forum (1 table -Posts-, count)</p>
<pre>
$post_count = $this->Post->find(
	'count',
	array(
		'conditions' => array('forum_id' => $id),
		'recursive' => -1
	)
);
</pre>
<p>With using count, there is no need to get fields or sort order, all we really need to do is get the conditions set, which are: all posts with the selected forum_id value. This returns a number of the records returned. Let&#8217;s say for this example it returned 12. </p>
<p>3. The last post, and who posted it, in the selected forum (3 tables -Users Posts Forums- , 1 record, certain fields)<br />
For this we can do a trick in the query, instead of getting just all the records, or the last entered one, we could try this:</p>
<pre>
$lastP = $this->Post->find(
	array('Post.forum_id' => $id), //array of conditions
	array('Post.created', 'User.username', 'Post.parent_topic', 'Post.title', 'Post.post_id', 'Forum.forum_name'), //array of field names
	'Post.created DESC', //string or array defining order
	-1, //int recursive level
	1 //int number of records to return
);
</pre>
<p>This is going to query the tables, where these conditions are met, order them descending order, and then return 1 record, the first one, which will be the last entry made in the table with that forum_id. Now we get into the &#8220;meat&#8221; of this thing. </p>
<p>4. All posts in a forum topic, paginate results (3 tables, all records on specific conditions, certain fields)</p>
<pre>
// Get the parent post
$parent = $this->Post->find(
	array('Post.post_id' => $id),
	array('Post.post_id', 'Post.forum_id', 'Post.title', 'Post.details', 'Post.created', 'User.username', 'User.avatar', 'User.biography', 'User.created', 'Forum.name'),
	'Post.created DESC',
	0
);
</pre>
<p>In this example, and as <a href="http://www.hirdweb.com/2008/08/04/custom-pagination-in-cakephp/">previously noted in my earlier blog posts</a>, the &#8220;Topic&#8221; is an entry in the Posts table, and all replies to that post reside in the same table, but reference that post_id as the parent_topic value. So the first thing I do is get this &#8220;Topic&#8221; information. I do some checks on this (which is outside the scope of this entry). Then I am ready to grab the replies to this topic, and then paginate the results. Since I already referenced the controller to use the paginator, I need to make a call to the paginator, and I need to apply a condition to it:</p>
<pre>
// grab all of the posts for this parent topic, and get the parent topic in the pagintor
$cond = array( 'OR' =>array( 'Post.parent_topic' => $id, 'Post.post_id' => $id ) );
$this->set( 'posts', $this->paginate( "Post", $cond ) );
</pre>
<p>One of the important things to note in this query, is the use of the $cond variable. I set this to use an &#8220;OR&#8221; clause. If nothing is specified, then the find() or paginator() assumes it is an &#8220;AND&#8221; clause, which is not the case here. So I set the conditions to look for the the $id value in either the post_id or the parent_topic columns. Be sure to check out the Cookbook for more information on complex queries. </p>
<p>But that is about it. Real world examples in use today using the new find() methods. The best part about these, is that with a little tweak here or there, you can have queries do what you want them to do, with little coding needed to accomplish the task. </p>

<!-- Wordpress Connect Modules v1.05 -->]]></content:encoded>
			<wfw:commentRss>http://www.hirdweb.com/2008/08/18/queries-using-cakephp-find/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>AJAX and YUI</title>
		<link>http://www.hirdweb.com/2008/08/11/ajax-and-yui/</link>
		<comments>http://www.hirdweb.com/2008/08/11/ajax-and-yui/#comments</comments>
		<pubDate>Mon, 11 Aug 2008 13:53:17 +0000</pubDate>
		<dc:creator>stephen</dc:creator>
				<category><![CDATA[Applications]]></category>
		<category><![CDATA[Ideas and Sorts]]></category>
		<category><![CDATA[AJAX]]></category>
		<category><![CDATA[Code]]></category>
		<category><![CDATA[html]]></category>
		<category><![CDATA[YUI]]></category>

		<guid isPermaLink="false">http://www.hirdweb.com/?p=11</guid>
		<description><![CDATA[With the sensationalized aura surrounding this &#8220;web 2.0&#8243; myth, there is more and more of a call for AJAX enabled sites. This demand gets higher due to sites like Facebook, MySpace, Twitter, and so forth. So when going forward with a design to implement AJAX libraries, which one is the best. The answer: Whichever one [...]]]></description>
			<content:encoded><![CDATA[<p>With the sensationalized aura surrounding this &#8220;web 2.0&#8243; myth, there is more and more of a call for AJAX enabled sites. This demand gets higher due to sites like Facebook, MySpace, Twitter, and so forth. So when going forward with a design to implement AJAX libraries, which one is the best. The answer: Whichever one fits the job at hand. There are good points to Scriptaculous, jQuery DoJo and others. There is a good list of some of these with pros and cons at <a href="http://chandlerproject.org/Projects/AjaxLibraries" target="_blank">The Chandler Project</a>, and a further list of other libraries at <a title="eDevils Weblog" href="http://edevil.wordpress.com/2005/11/14/javascript-libraries-roundup/" target="_blank">eDevil&#8217;s Weblog</a>.</p>
<p>The one I am going to cover is a newer one, and one that is hosted elsewhere, which has its own pros and cons, and that is the Yahoo User Interface, or YUI. The documentation, the downloads (if you desire), tutorials and other information is located at <a href="http://developer.yahoo.com/yui/" target="_blank">http://developer.yahoo.com/yui/</a> and is very extensive for the different aspects it can do.  What I am going to cover is something useful for long pages of content on the web, Tabbed Viewing.</p>
<p><span id="more-11"></span></p>
<p>Tabbed viewing allows for a load of content, to be displayed parts at a time, then when a user needs the next piece of information, they can click on a tab, and then new content is available without having to reload the page. The YUI provides great tutorials for these, and examples, with code. It is located at: <a href="http://developer.yahoo.com/yui/examples/tabview/index.html" target="_blank">http://developer.yahoo.com/yui/examples/tabview/index.html</a>. Since the web is polluted with duplicates, I will not do that, but will instead show what I have done with this. I used the  &#8220;build from markup&#8221; path on this one.</p>
<p>First you have your content. Now if this was really long content, we could break this up in 4 tabs. We would add the YUI libraries to be used, the following needs to be included:</p>
<pre>
&lt;!-- This will bring in the font styles for the tab and content from the YUI hosted styles --&gt;
&lt;link rel="stylesheet" type="text/css" href="http://yui.yahooapis.com/2.5.1/build/fonts/fonts-min.css" /&gt;
&lt;!-- This will bring in the style for the tabs from the YUI hosted styles --&gt;
&lt;link rel="stylesheet" type="text/css" href="http://yui.yahooapis.com/2.5.1/build/tabview/assets/skins/sam/tabview.css" /&gt;

&lt;!-- The dependencies for the tab view --&gt;
&lt;script type="text/javascript" src="http://yui.yahooapis.com/2.5.1/build/yahoo-dom-event/yahoo-dom-event.js"&gt;&lt;/script&gt;
&lt;script type="text/javascript" src="http://yui.yahooapis.com/2.5.1/build/element/element-beta-min.js"&gt;&lt;/script&gt;

&lt;!-- Source library for the tab view --&gt;
&lt;script type="text/javascript" src="http://yui.yahooapis.com/2.5.1/build/tabview/tabview-min.js"&gt;&lt;/script&gt;</pre>
<p>In order to do dynamic loading, dynamic tab building and loading, there needs to be more libraries called, and you can see that in the YUI reference pages. </p>
<p>Now comes the styling. Since not every page will need to styled the way Yahoo! thinks it should be, I found some tags that I have replaced with inline CSS. </p>
<pre>
&lt;style type="text/css"&gt;
.yui-navset {width: 802px; }
.yui-skin-sam .yui-navset .yui-nav, .yui-skin-sam .yui-navset .yui-navset-top .yui-nav { border-color:#38487C; border-style:solid; border-width:0pt 0pt 5px; }
.yui-skin-sam .yui-navset .yui-nav .selected a, .yui-skin-sam .yui-navset .yui-nav .selected a em { font-weight:bold; }
.yui-skin-sam .yui-navset .yui-nav .selected a, .yui-skin-sam .yui-navset .yui-nav .selected a:focus, .yui-skin-sam .yui-navset .yui-nav .selected a:hover { background:#38487C; color:#FECE55; }
.yui-skin-sam .yui-navset .yui-nav a:hover,
.yui-skin-sam .yui-navset .yui-nav a:focus {
    background:#A5B7D8 url(../../../../assets/skins/sam/sprite.png) repeat-x left -1300px; /* selected tab background */
    outline:0;
}
.yui-skin-sam .yui-navset .yui-content,.yui-skin-sam .yui-navset .yui-navset-top .yui-content{border:0px solid #808080; border-top-color:#243356; padding:0.25em 0.5em;}
.yui-skin-sam .yui-navset-left .yui-content{border:1px solid #808080;border-left-color:#243356;}
.yui-skin-sam .yui-navset-bottom .yui-content,.yui-skin-sam .yui-navset .yui-navset-bottom {border:1px solid #808080;border-bottom-color:#243356;}
.yui-skin-sam .yui-navset .yui-content{background:#FFFFFF;}
.yui-navset .yui-content{zoom:1;}
.yui-content{border:0px solid #808080;border-bottom-color:#243356;}
&lt;/style&gt;
</pre>
<p>By resetting these, it will overwrite the styles for the tabs, the content area and the hover properties. Again, if you are fine with the Yahoo! method, that is fine. If not, these tags should help you on your own theme style. </p>
<p>It is important to ID the tab area DIV tag what you call out in the TabView() method. Add DIV tags to surround the tabbed area to set up a &#8220;boundary&#8221;. And then add the DIV tag for the tabbed area to be placed inside.
<pre>
&lt;div class='yui-skin-sam'&gt;
    &lt;div id='content_area_name' class='yui-navset'&gt;
         ALL CONTENT WOULD GO HERE
    &lt;/div&gt;
&lt;/div&gt;</pre>
<p>Now the tabs. The tabs are UL and LI elements styled up. They are the first things in the DIV &#8216;content_area_name&#8217; tag.</p>
<pre>
&lt;ul class="yui-nav"&gt;
    &lt;li class="selected"&gt;&lt;a href="#content1"&gt;&lt;em&gt;Content One&lt;/em&gt;&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="#content2"&gt;&lt;em&gt;Content Two&lt;/em&gt;&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="#content3"&gt;&lt;em&gt;Content Three&lt;/em&gt;&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="#content4"&gt;&lt;em&gt;Content Four&lt;/em&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</pre>
<p>You can choose which tab shows up first by adding the &#8220;selected&#8221; class to the LI tag. The EM tags are important to provide the padding and the spacing for the tabs. If you choose to leave those out, the text in the tabs will have no spacing and the tabs will lose some of their styling.</p>
<p>Now we add a DIV tag to show the content area for each tab, then a DIV tag with the ID of the href listed above for each tab section. </p>
<pre>
&lt;div class="yui-content"&gt;
    &lt;div id="content1"&gt;
    CONTENT GOES HERE
    &lt;/div&gt;

    &lt;div id="content2"&gt;
	CONTENT GOES HERE
    &lt;/div&gt;

    &lt;div id="content3"&gt;
	CONTENT GOES HERE
    &lt;/div&gt;

    &lt;div id="content4"&gt;
	CONTENT GOES HERE
    &lt;/div&gt;
&lt;/div&gt;
</pre>
<p>We need to include the script to call out the DIV area for the tabbed events, and content in these tabs.
<pre>
&lt;script&gt;
    (function() {
        var tabView = new YAHOO.widget.TabView('content_area_name');
    })();
&lt;/script&gt;</pre>
<p>And that should create the tabs, content is now available and will load the different tabs without reloading the page. </p>
<p>The entire code would look like this now:</p>
<pre>
&lt;!-- This will bring in the font styles for the tab and content from the YUI hosted styles --&gt;
&lt;link rel="stylesheet" type="text/css" href="http://yui.yahooapis.com/2.5.1/build/fonts/fonts-min.css" /&gt;
&lt;!-- This will bring in the style for the tabs from the YUI hosted styles --&gt;
&lt;link rel="stylesheet" type="text/css" href="http://yui.yahooapis.com/2.5.1/build/tabview/assets/skins/sam/tabview.css" /&gt;

&lt;!-- The dependencies for the tab view --&gt;
&lt;script type="text/javascript" src="http://yui.yahooapis.com/2.5.1/build/yahoo-dom-event/yahoo-dom-event.js"&gt;&lt;/script&gt;
&lt;script type="text/javascript" src="http://yui.yahooapis.com/2.5.1/build/element/element-beta-min.js"&gt;&lt;/script&gt;

&lt;!-- Source library for the tab view --&gt;
&lt;script type="text/javascript" src="http://yui.yahooapis.com/2.5.1/build/tabview/tabview-min.js"&gt;&lt;/script&gt;

&lt;style type="text/css"&gt;
.yui-navset {width: 802px; }
.yui-skin-sam .yui-navset .yui-nav, .yui-skin-sam .yui-navset .yui-navset-top .yui-nav { border-color:#38487C; border-style:solid; border-width:0pt 0pt 5px; }
.yui-skin-sam .yui-navset .yui-nav .selected a, .yui-skin-sam .yui-navset .yui-nav .selected a em { font-weight:bold; }
.yui-skin-sam .yui-navset .yui-nav .selected a, .yui-skin-sam .yui-navset .yui-nav .selected a:focus, .yui-skin-sam .yui-navset .yui-nav .selected a:hover { background:#38487C; color:#FECE55; }
.yui-skin-sam .yui-navset .yui-nav a:hover,
.yui-skin-sam .yui-navset .yui-nav a:focus {
    background:#A5B7D8 url(../../../../assets/skins/sam/sprite.png) repeat-x left -1300px; /* selected tab background */
    outline:0;
}
.yui-skin-sam .yui-navset .yui-content,.yui-skin-sam .yui-navset .yui-navset-top .yui-content{border:0px solid #808080; border-top-color:#243356; padding:0.25em 0.5em;}
.yui-skin-sam .yui-navset-left .yui-content{border:1px solid #808080;border-left-color:#243356;}
.yui-skin-sam .yui-navset-bottom .yui-content,.yui-skin-sam .yui-navset .yui-navset-bottom {border:1px solid #808080;border-bottom-color:#243356;}
.yui-skin-sam .yui-navset .yui-content{background:#FFFFFF;}
.yui-navset .yui-content{zoom:1;}
.yui-content{border:0px solid #808080;border-bottom-color:#243356;}
&lt;/style&gt;

&lt;div class='yui-skin-sam'&gt;
    &lt;div id='content_area_name' class='yui-navset'&gt;
        &lt;ul class="yui-nav"&gt;
            &lt;li class="selected"&gt;&lt;a href="#content1"&gt;&lt;em&gt;Content One&lt;/em&gt;&lt;/a&gt;&lt;/li&gt;
            &lt;li&gt;&lt;a href="#content2"&gt;&lt;em&gt;Content Two&lt;/em&gt;&lt;/a&gt;&lt;/li&gt;
            &lt;li&gt;&lt;a href="#content3"&gt;&lt;em&gt;Content Three&lt;/em&gt;&lt;/a&gt;&lt;/li&gt;
            &lt;li&gt;&lt;a href="#content4"&gt;&lt;em&gt;Content Four&lt;/em&gt;&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;

        &lt;div class="yui-content"&gt;
	    &lt;div id="content1"&gt;
	    CONTENT GOES HERE
	    &lt;/div&gt;

	    &lt;div id="content2"&gt;
            CONTENT GOES HERE
	    &lt;/div&gt;

	    &lt;div id="content3"&gt;
	    CONTENT GOES HERE
	    &lt;/div&gt;

	    &lt;div id="content4"&gt;
	    CONTENT GOES HERE
	    &lt;/div&gt;
        &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;
&lt;script&gt;
    (function() {
        var tabView = new YAHOO.widget.TabView('content_area_name');
    })();
&lt;/script&gt;
</pre>
<p>You can put all of the code inside the BODY tags, and sometimes you have to based on templates being used. Or you can take the CSS, JavaScript calls, and inline styles, put those in the HEADER tags, and put the rest in the BODY tags. </p>
<p>Here are a couple of sample pages with the YUI Tab View, both in their styles, and in the new style listed above. </p>
<p><a href="http://www.hirdweb.com/samples/yui_style.php">YUI Styled Tab View</a></p>
<p><a href="http://www.hirdweb.com/samples/custom_style.php">Custom Style Tab View</a></p>

<!-- Wordpress Connect Modules v1.05 -->]]></content:encoded>
			<wfw:commentRss>http://www.hirdweb.com/2008/08/11/ajax-and-yui/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Don&#8217;t forget the basics</title>
		<link>http://www.hirdweb.com/2008/07/21/dont-forget-the-basics/</link>
		<comments>http://www.hirdweb.com/2008/07/21/dont-forget-the-basics/#comments</comments>
		<pubDate>Mon, 21 Jul 2008 23:57:27 +0000</pubDate>
		<dc:creator>stephen</dc:creator>
				<category><![CDATA[Applications]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Code]]></category>
		<category><![CDATA[debug]]></category>
		<category><![CDATA[PEAR]]></category>
		<category><![CDATA[testing]]></category>
		<category><![CDATA[trouble-shooting]]></category>

		<guid isPermaLink="false">http://www.hirdweb.com/?p=8</guid>
		<description><![CDATA[There was something I was asked to troubleshoot between two different environments. Most reputable places will give at least 2 different environments for application development, the best is to have at least three, development, stage, and production areas. I was asked resolve and fix an issue in the stage area, but it was not happening [...]]]></description>
			<content:encoded><![CDATA[<p>There was something I was asked to troubleshoot between two different environments. Most reputable places will give at least 2 different environments for application development, the best is to have at least three,  development, stage, and production areas.  I was asked resolve and fix an issue in the stage area, but it was not happening in the development area. Normally, I follow a few simple rules to get through this type of troubleshooting. Today, for some reason, I blew those off. Now this is not an end all be all type of list, and I use what is good for me and what I have learned. Other people may find different ways to do this, and find ways that work for them more. Here are some of the major items I check for with web applications in PHP.</p>
<ul>
<li>Check the Apache services, connection, or anything that would lead to just no resulting page whatsoever.</li>
<li>Check the DB server, make sure the server is working, the connection is good, the data flow is there</li>
<li>Check the permission of the database, the tables, the sequences, etc. Whatever is needed from the database, make sure the caller has permissions to do that task</li>
<li>Check the code objects/PEAR packages/framework extensions are installed. If you have a recent version of PHP, then you should be good for PEAR, and if you have the most recent framework version (like Symfony, CakePHP or Zend) that should house them all, but never hurts to check</li>
<li>Check instantiated objects, function calls, object variables, etc. Most of the time it could be a spelling error, or the call is made before the object is created</li>
<li>I check the data being returned and the statements making the calls. What I am calling for may not be listed, or I may need to grab data from another table. This sometimes creates errors for other functions expecting an array and getting a character value.</li>
<li>Dump the session, maybe the session variable was never set, or never started.</li>
<li>Form data and POST variables are always good to give a good ol&#8217; var_dump() or print_r().</li>
</ul>
<p>Obviously this is not all of them, nor is this just a quick checklist. Some of these may take a while to go through, and may have a lot of details to peruse through to find the answer. This will not always give the answer the quickest ways, nor will it ever just shine the answer down to you. But it helps to isolate issues starting form the global level, work down to the application level, and then down to the code level. Plus, it helps eliminate the obvious problems first, so that when someone asks <em>&#8220;is the printer is turned on?&#8221;</em>, I don&#8217;t sit there looking stupid because &#8220;it is turned off&#8221; and I just never looked. But that is what happens at times. </p>
<p>Today, I completely forgot about permissions on a database. Sure, the code works in development, I have my hands all over that environment. But when it does not work in the staging area, I should have checked permissions instead of just lopping off my hand with endless queries to try and see where the code went wrong. Just one simple act of a GRANT permission to the application user calling the query would have fixed it. But I was forgetful and should have checked that first. Sometimes developers go down the wrong path. To stay down the wrong path, well, you can finish that one on your own. </p>

<!-- Wordpress Connect Modules v1.05 -->]]></content:encoded>
			<wfw:commentRss>http://www.hirdweb.com/2008/07/21/dont-forget-the-basics/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>
