Archive for July, 2009

Published by Rolf on 22 Jul 2009

Search-engine-friendly URL’s using the Jake bridge

A few months ago I posted my experience using the Jake bridge between CakePHP and Joomla. Overall it’s pretty slick, but with one annoyance: the URL’s are not search-engine-friendly. Moreover they broadcast your frameworks of choice which is not a good from a security viewpoint.

So after much research into the Joomla component routing and how the framework parses SEF URL’s, I came up with the following upgrade to Jake, which allows much prettier URLs.

This presumes that you have your Cake app installed in a subdirectory of your Joomla webroot (assume it’s “/webapp”). Secondly, decide upon the SEF base you want to use – it must be different from the former since you want to force it to route the request through Joomla and that requires a path that doesn’t correspond to a physical directory (I chose “/app” to be nondescript).

  1. Update your /.htaccess file to add a rewrite rule, before the core SEF section, for this new SEF base path:
    ...
    RewriteBase /
     
    # For Jake: redirect everything that starts with app/
    # See http://www.phpbb-seo.com/en/apache-mod-rewrite/article3226.html for more details
    RewriteRule	^app\/(.*)$	/index.php?option=com_jake&jrun=/$1		[QSA,L]
     
    ########## Begin - Joomla! core SEF Section
    #
    ...
  2. In /components/lib/cake_embedded_dispatcher_class.php:597, replace _changeUrl() with the following:
             /**
    	* Base for SEF URI's
    	*
    	* @since 1.1
    	* @var string
    	*/
    	var $sefCakeApplicationBase = null;
     
    	/**
    	 * Set base path to CakePHP application, using SEF URL's.
    	 *
    	 * @param string $base	Base path to Cake application in SEF URI
    	 *
    	 * @access public
    	 * @since 1.1
    	 */
    	function setSefCakeApplicationBase($base)
    	{
    		$this->sefCakeApplicationBase = $base;
    	}
     
    	function _changeUrl($start, $p1, $url, $p3, $ending, $startUrl='href="', $endUrl='"', $useComponent = true, $clean = false)
    	{
    		if (isset($this->sefCakeApplicationBase))
    		{
    			$newUrl = $this->sefCakeApplicationBase . $url;
    		}
    		else
    		{
    			// Patterns to match URLs that should not pass through the component
     
    			$passThroughLinksMatching = array('/\.jpg$/i', '/\.png$/i', '/\.gif$/i', '/\.pdf$/i', '/\.rss$/i');
     
    			if ($useComponent && isset($passThroughLinksMatching))
    			{
    				foreach($passThroughLinksMatching as $element)
    				{
    					if (preg_match($element, $url))
    					{
    						$useComponent = false;
    						break;
    					}
    				}
    			}
     
    			if ($useComponent)
    			{
    				$newUrl = str_replace('$CAKE_ACTION', urlencode($url), $this->component);
     
    				if (!empty($this->cakeUrlAddParameters))
    				{
    					$newUrl .= '&' . $this->cakeUrlAddParameters;
    				}
     
    				if ($clean)
    				{
    					$newUrl .= '&' . $this->cleanOutputParameter;
    				}
    			}
    			else
    			{
    				$newUrl = $this->cakeUrlBase . $url;
    			}
    		}
     
    		$newUrl = str_replace('&', '&', $newUrl);
     
    		$result = $start . $p1;
    		$result .= $startUrl . $newUrl . $endUrl;
    		$result .= $p3 . $ending;
     
    		$result = stripslashes($result);
     
    		return $result;
    	}
  3. In /components/lib/jake.class.php:160, add this new method to be used in place of getUrl():
             **
    	 * Gets the SEF URL to execute the specified CakePHP action with Jake
    	 *
    	 * @param string $action	CakePHP URL. (leave empty for default cake action)
    	 *
    	 * @return string	A valid Jake URL
    	 *
    	 * @access public
    	 * @since 1.1
    	 */
    	function getSefUrl($action = '', $sefCakeApplicationBase = '')
    	{
    		return $this->joomlaUrl . $sefCakeApplicationBase . $action;
    	}
  4. In /components/com_jake/jake_front_component_class.php:89, add these lines:
    		// Set the SEF URL to match the rewrite rule in /.htaccess
    		$cakeDispatcher->setSefCakeApplicationBase('/app');
  5. And finally, in your app_controller.php, you can “Jakeify” an ordinary CakePHP URL to the new SEF base, with the simple function:
    	function jakeify($url)
    	{
    		if (defined('JAKE'))
    		{
    			// set this to the same SEF base defined in /.htaccess
    			$url = $this->jake->getSefUrl($url, '/app');
    		}
    		return $url;
    	}

Once you do this, your CakePHP URIs, running through Joomla, become the much friendlier /app/controllername/actionname instead of /components/jake/?jrun=controllername/actionname. You can still access the CakePHP URI’s directly via /webapp/controllername/actionname, just as before.

Published by Rolf on 17 Jul 2009

Setting permissions on directories in Windows Vista

Lots of times, when installing web applications, you need to make specific directories writable by all users (in particular, the user running Apache). By default, though, this isn’t the case when you create directories in Windows. And the Properties window has a “Read Only” checkbox, but setting it has never seemed to work for me.

I found this workaround. It involves cygwin; perhaps there’s a simpler way.

  1. Right-click the directory and go to Properties.
  2. Click the Security tab
  3. Highlight “Everyone” and click the Edit button
  4. Click “Allow” for full control
  5. OK out
  6. Now, with cygwin, you can set the permissions on that directory (e.g., “chmod 777 -R /path/to/my/directory”)

That’s it.

UPDATE (10/7/09):

I noticed today that this doesn’t always seem to recursively set the permissions. You can do the same thing command-line at an Admin prompt:

cacls c:\path\to\directory /T /G Everyone:F

Published by Rolf on 03 Jul 2009

Adding subdomains to a Plesk-managed domain

I alluded to this in an earlier post, but if you want to add a new subdomain to a domain, you have to add the DNS entry to the zone manually (i.e., just doing “Create Subdomain” isn’t sufficient). The steps are:

  1. Create the subdomain in the Plesk Control Panel, under Domains -> <DOMAIN NAME> -> Subdomains
  2. Open the Parallels Business Automation control panel, and under System -> Domain Management -> All My Domains -> Domain Name, choose the “DNS Zone” tab.
  3. Click “New Record”
  4. Enter the name, choose type A, and set the value to the same IP address as everything else.

Now, once you give your ISP a chance to catch up on the propagation, your new subdomain should be available.