<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss 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/" xmlns:series="http://organizeseries.com/" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0">

<channel>
	<title>PHP Master</title>
	
	<link>http://phpmaster.com</link>
	<description>For PHP Developers | PHP Tutorials | Learn PHP | PHP Script | Security | PHP Date and Forms</description>
	<lastBuildDate>Fri, 24 May 2013 14:30:42 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.5.1</generator>
		<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/PHPMaster_feed" /><feedburner:info uri="phpmaster_feed" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><item>
		<title>Extract OLE Objects from an Access Database using PHP, Part 1</title>
		<link>http://feedproxy.google.com/~r/PHPMaster_feed/~3/ocS4wVVD8sY/</link>
		<comments>http://phpmaster.com/extract-ole-objects-from-an-access-database-using-php-1/#comments</comments>
		<pubDate>Fri, 24 May 2013 14:30:42 +0000</pubDate>
		<dc:creator>David Francis</dc:creator>
				<category><![CDATA[Intermediate]]></category>
		<category><![CDATA[PHP Tutorials]]></category>
		<category><![CDATA[Database]]></category>
		<category><![CDATA[Windows]]></category>

		<guid isPermaLink="false">http://phpmaster.com/?p=5689</guid>
		<description><![CDATA[The storage of a blob in a database is never a simple matter, and Microsoft's Access database is no exception. Many programmers who need to migrate from legacy Access databases are stumped when confronted with the task of extracting files from OLE Object fields. In this series you'll see how PHP can be used to extract objects from two OLE types: packages and Acrobat PDF documents. Part 1 focuses on OLE packages.]]></description>
				<content:encoded><![CDATA[<p>A simple search of the Web reveals that there are many programmers who need to work with legacy databases, such as Microsoft Access, but are stumped when confronted with the task of extracting files from Access&#8217;s OLE Object field. Part of the problem is the dearth of readily available information about how objects are stored in the OLE field.</p>
<p>Worse still for the PHP programmer is that every instance of queries posted to forums and support websites are from non-PHP programmers – .Net seems to be the most common, and there are also questions from Java and Delphi programmers.</p>
<p>One thing all of these developers have in common though is the need to extract information from these troublesome OLE fields in order to migrate from a legacy database. But not one article specifically targets for PHP programmers. Nor do any of them address &#8220;packages&#8221;, only specific data types such as JPEG, PNG, GIF, etc.</p>
<p>In this article we&#8217;ll see how PHP can be used to extract objects from two OLE types: packages and Acrobat PDF documents. This is the first part of a two-part series in which we&#8217;ll look at OLE packages, which, as we&#8217;ll see, can be identified as either “Package” or “Packager Shell Object”. Values expressed in this article are based on an Access 2000 database.</p>
<h2>OLE Container</h2>
<p>The storage of a blob (binary large object) in a database is never a simple matter, and Microsoft&#8217;s Access database is no exception. Let&#8217;s summarize some key aspects of the OLE container used when an object is inserted to an OLE field in Access:</p>
<ul>
<li>No external file would have been inserted to an Access OLE field without first being wrapped in a container. For our purposes, this container can be considered to be a  header in front of the object we are interested in and a trailer after it.</li>
<li>The header length is not fixed. Even for the OLE package type the header length can be different depending on the object that is embedded in the container.</li>
<li>The data is not in a human-readable form, making it harder to visually find crucial items such as the original name of the embedded object, or its name, or the start of the object component.</li>
<li>The trailer can be ignored. Our focus here will be on the header and object components.</li>
</ul>
<p>One other point: it&#8217;s not just the object component that&#8217;s encoded, but the header is too. Before we can make any sense of any of the data, the header needs to be decoded first.</p>
<h2>Encoded Header and Data</h2>
<p>The test database is defined as simply as possible, with the embedded files contained in the <code>image</code> field of <code>Table1</code>:</p>
<p><img src="http://cdn.phpmaster.com/files/2013/05/ole01-1.png" alt="ole01-1" width="266" height="84" class="aligncenter size-full wp-image-5694"  style="float:none !important; margin-left: auto; margin-right: auto;"/></p>
<p>Throughout this worked example, we&#8217;ll be using an Apache logo GIF that I stored in the OLE field. Extracting the field contents without decoding, then inspecting the output in a hexadecimal viewer reveals, well, gibberish:</p>
<p><img src="http://cdn.phpmaster.com/files/2013/05/ole01-2.png" alt="ole01-2" width="600" class="aligncenter size-full wp-image-5695" style="float:none !important; margin-left: auto; margin-right: auto;"/></p>
<p>After converting the extracted header from hexadecimal to decimal encoding using PHP&#8217;s <code>hex2dec()</code> function we have something more useful:</p>
<p><img src="http://cdn.phpmaster.com/files/2013/05/ole01-3.png" alt="ole01-3" width="600" class="aligncenter size-full wp-image-5696" style="float:none !important; margin-left: auto; margin-right: auto;"/></p>
<p>It looks uninviting, but it&#8217;s clear that we can now make some sense of the data. To help simplify matters the first 20 bytes can be ignored.</p>
<p>The next block of characters tells us that the OLE object is of type Packager Shell Object. An OLE package is a general purpose container for those file types not recognized by the database when the files were inserted.</p>
<p>In the words of Professor Farnsworth, “Good news, everyone!” If we look closer at the ASCII column of the hex dump we can see the name of the original file that is embedded in the container – <code>apache_02.gif</code>. This will be useful later when we try to locate the end of the header and the start of the data that we need to extract. Even better, the filename always starts at byte 84 of a Packager Shell Object header and at byte 70 of a Package header.</p>
<p>Before moving on to how we extract the GIF from the package, here&#8217;s a little teaser: In both of these two hex dumps, there&#8217;s the sequence 0A0600 underlined in yellow. For now, accept that 0A0600 is important. We&#8217;ll see why in a moment.</p>
<h2>Extracting the Object</h2>
<p>Before we can extract the embedded object, we need to know where it starts and ends in the data. Careful inspection of the hexadecimal representation reveals that the character sequence for the filename occurs three times – once at byte 84 (or 70), then again twice as part of the full path.</p>
<p><img src="http://cdn.phpmaster.com/files/2013/05/ole01-4.png" alt="ole01-4" width="600" class="aligncenter size-full wp-image-5697" style="float:none !important; margin-left: auto; margin-right: auto;"/></p>
<p>At least, that how it seems in this example. Just to complicate matters, it&#8217;s possible that the full path may appear only once. Also, Access may have changed the case of the file path, or changed each level of the file path to old-fashioned 8:3 format (meaning that names longer than 8 character will be truncated, and characters 7 and 8 replaced by ~1).Fortunately there will always be an instance of the full path somewhere around the location of the second full path in this example. “Somewhere around the location?” Just as the header length is not fixed, so too are the locations of the full path. We need to work around these niggles.</p>
<p>“More good news, everyone!” The final instance of the filename is the second last important item of interest in the header. It is null-terminated (00), after which is the hexadecimal sequence 0A0600 we saw earlier. This the original size in bytes of the embedded object. It&#8217;s stored in little-endian format, so this needs to be reversed to big-endian before we can use it: 0A0600 becomes 00060A, which means 1,546 bytes. This group of three bytes gives a maximum allowable embedded file size of 16 MB.</p>
<p>After this sequence is the object we need. It starts with the character sequence 474946383961. Converting this to ASCII yields “GIF89a”. It doesn&#8217;t show in the ASCII column because Access does not store data in the OLE header in consistent two-character blocks. That&#8217;s why the first instance of the full path displays nicely up to “\Documents\Wri” then goes awry. In this example, the character after “Wri” ought to be “t” as in “Writing” but Access inserted a null character into the sequence. Why? Yeah, Microsoft, why! Note that “ting” (74646E67) immediately follows the null. Another niggle to code around.</p>
<p>So let&#8217;s recap. What do we have now? We have the original name of the embedded file, the size in bytes of the original file, and we have the start location of the data we need to extract. We thus have all we need to extract the embedded file from a legacy Access database, and then save it to disc using its original name and extension.</p>
<h2>Putting Theory into Practice</h2>
<p>What follows is the PHP I used to extract from my test database the object details we discussed above. It&#8217;s no-frills, procedural PHP which should be easy for anyone to understand the steps involved in extracting an object from an OLE package.</p>
<p>You&#8217;ll notice that some of the logic has multiplied certain numbers by a factor of two. For example, the offset for the embedded file name is defined as 168 rather than the 84 bytes mentioned above. That&#8217;s because some parts of the code work on the raw data from the Access database&#8217;s OLE field, which is encoded in hexadecimal format. That is, each single byte is stored as two hexadecimal characters.</p>
<pre class="brush: php; title: ; notranslate">&lt;?php
if (!function_exists(&quot;hex2bin&quot;)) {
   function hex2bin($hexStr) {
      $hexStrLen = strlen($hexStr);
      $binStr = &quot;&quot;;
      $i = 0;
      while ($i &lt; $hexStrLen) {
         $a = substr($hexStr, $i, 2);
         $c = pack(&quot;H*&quot;, $a);
         $binStr .= $c;
         $i += 2;
      }
      return $binStr;
   }
}

$dbName = &quot;db1.mdb&quot;;
$db = new PDO(&quot;odbc:DRIVER={Microsoft Access Driver (*.mdb)}; DBQ=$dbName; Uid=; Pwd=;&quot;);

$sql = &quot;SELECT * FROM Table1 WHERE id = 2&quot;;
foreach ($db-&gt;query($sql) as $row) {
   $objName = &quot;&quot;;

   switch (getOLEType($row[&quot;image&quot;])) {
      case &quot;Packager Shell Object&quot;:
          list($objName, $objData) = extractPackagerShellObject($row[&quot;image&quot;]);
          break;
      case &quot;Package&quot;:
          list($objName, $objData) = extractPackage($row[&quot;image&quot;]);
          break;
      default:
          throw new Exception(&quot;Unknown OLE type&quot;);
   }
   if ($objName != &quot;&quot;) {
      file_put_contents($objName, $objData);
   }
}

function flipEndian($data, $size) {
   $str = &quot;&quot;;
   for ($i = $size - 2; $i &gt;= 0; $i -= 2) {
      $str .= substr($data, $i, 2);
   }
   return $str;
}

function findNullPos($str) {
   // must start on a two-character boundary
   return floor((strpos($str, &quot;00&quot;) + 1) / 2) * 2;
}

function getOLEType($data) {
   // fixed position of OLE type
   $offset = 40;

   $tmp = substr($data, $offset, 255);
   $nullPos = findNullPos($tmp);
   $tmp = substr($tmp, 0, $nullPos);
   $type = hex2bin($tmp);

   return $type;
}

function extractPackagerShellObject($data) {
   $headerBlock = 500; // usable header size
   $offset = 168; // location of name

   // find name
   $tmp = substr($data, $offset, 255);
   $nullPos = findNullPos($tmp);
   $name = substr($tmp, 0, $nullPos);
   $pos = $offset + strlen($name);

   // find data
   $path1 = strpos($data, $name, $pos); // 1st full path
   $pos = $path1 + strlen($name);
   $path2 = strpos($data, $name, $pos); // 2nd full path
   // check if only one full path
   if ($path2 &gt; $pos) {   
      $pos = $path2 + strlen($name);
   }
   $oleSizePos = $pos + 2;
   $oleObjSize = flipEndian(substr($data, $oleSizePos, 8), 8);
   $oleHeaderEnd = $oleSizePos + 8;
   $objName = hex2bin(substr($tmp, 0, $nullPos));

   // extract object
   $data = substr($data, $oleHeaderEnd, hexdec($oleObjSize) * 2);
   $objData = hex2bin($data);

   return array($objName, $objData);
}

function extractPackage($data) {
   $headerBlock = 500; // usable header size
   $offset = 140; // location of name

   // find name
   $tmp = substr($data, $offset, 255);
   $nullPos = findNullPos($tmp);
   $name = substr($tmp, 0, $nullPos);
   $pos = $offset + strlen($name);

   // find data
   $path1 = strpos($data, $name, $pos); // 1st full path
   $pos = $path1 + strlen($name);
   $path2 = strpos($data, $name, $pos); // 2nd full path
   // check if only one full path
   if ($path2 &gt; $pos) {   
      $pos = $path2 + strlen($name);
   }
   $oleSizePos = $pos + 2;
   $oleObjSize = flipEndian(substr($data, $oleSizePos, 8), 8);
   $oleHeaderEnd = $oleSizePos + 8;
   $objName = hex2bin(substr($tmp, 0, $nullPos));

   // extract object
   $data = substr($data, $oleHeaderEnd, hexdec($oleObjSize) * 2);
   $objData = hex2bin($data);

   return array($objName, $objData);
}</pre>
<p>Note that the bespoke <code>hex2bin()</code> function is only required if your PHP installation does not have its own (it was added in PHP 5.4). Also, the <code>switch</code> statement makes the logic extensible, as we&#8217;ll discover in the next part of this article.</p>
<p>The two package functions look very similar. These will be revisited in the next part of this article, when the code will be refactored because of the similar nature of the logic required for these and other object types.</p>
<p>I have tested this PHP with the following file types: BMP, GIF, JPEG, PNG, DOC, XLS, and PPT, all of which were stored as packages. The logic presented above should allow any file stored in an OLE package to be rescued from a legacy database, not just the GIF used in this example.</p>
<h2>Summary</h2>
<p>In this article we have covered the essential elements of extracting package objects from OLE fields in a Microsoft Access database using PHP. Having learned the basic structure of an OLE object, and how to extract the file contained therein, the method presented above can be applied to other OLE types to ensure that as much data as possible can be retrieved from a legacy Access database.</p>
<p>In the second part of this series we&#8217;ll look at the more complex issue of extracting known object types, focusing in particular on extracting Acrobat PDF documents from a legacy Access database.</p>
<p><small>Image via <a title="Royalty Free Stock Photos at Fotolia.com" href="http://us.fotolia.com/?utm_source=sitepoint&amp;utm_medium=website_link&amp;utm=campaign=sitepoint" target="_blank">Fotolia</a></small></p>
<img src="http://feeds.feedburner.com/~r/PHPMaster_feed/~4/ocS4wVVD8sY" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://phpmaster.com/extract-ole-objects-from-an-access-database-using-php-1/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://phpmaster.com/extract-ole-objects-from-an-access-database-using-php-1/</feedburner:origLink></item>
		<item>
		<title>Openbiz Cubi: A Robust PHP Application Framework, Part 2</title>
		<link>http://feedproxy.google.com/~r/PHPMaster_feed/~3/so3gaTtZ6-I/</link>
		<comments>http://phpmaster.com/openbiz-cubi-a-robust-php-application-framework-2/#comments</comments>
		<pubDate>Tue, 21 May 2013 22:00:30 +0000</pubDate>
		<dc:creator>Rocky Swen</dc:creator>
				<category><![CDATA[Intermediate]]></category>
		<category><![CDATA[PHP Tutorials]]></category>
		<category><![CDATA[Frameworks]]></category>

		<guid isPermaLink="false">http://phpmaster.com/?p=5710</guid>
		<description><![CDATA[Openbiz Cubi is a robust PHP application framework giving developers the ability to create business applications with minimal effort. In part 2 of this series, you'll dive a bit deeper into the core architecture of the framework and see how to build your own module.]]></description>
				<content:encoded><![CDATA[<p>In the first part of this series we talked about the development challenges we face and how Openbiz Cubi can help by providing a solid, ready-to-use web application framework. In this part we&#8217;ll see how to build our own module and dive a bit deeper into the core architecture of the framework.</p>
<h2>Build the First Module</h2>
<p>Let’s get to the exciting part – creating a module; we&#8217;ll start with a simple customer editing page. On this page users can create, update, and delete customers.</p>
<p>First let’s make a database table <code>customer</code>. The SQL to create the table is:</p>
<pre class="brush: sql; title: ; notranslate">CREATE TABLE customer (
  id INTEGER NOT NULL AUTO_INCREMENT,
  name VARCHAR(64) NOT NULL,
  description VARCHAR(255) DEFAULT NULL,
  address VARCHAR(255) DEFAULT NULL,
  phone VARCHAR(20) DEFAULT NULL,
  fax VARCHAR(20) DEFAULT NULL,
  status INTEGER DEFAULT NULL,
  create_by INTEGER DEFAULT '1',
  create_time DATETIME DEFAULT NULL,
  update_by INTEGER DEFAULT '1',
  update_time DATETIME DEFAULT NULL,
  PRIMARY KEY (id)
)
ENGINE=InnoDB</pre>
<p>The next step to creating a module is to create the XML metadata files for the customer editing page. Here we use <code>gen_meta</code>, the metadata generation command under the <code>cubi/bin/tools</code> directory.</p>
<pre>/dev/cubi/bin/tools$ <strong>php gen_meta.php Default customer</strong></pre>
<p>You can simply press the Enter key to complete the wizard. After the command executes, the following files are generated:</p>
<p><strong>Module configuration file</strong></p>
<ul>
<li><code>modules/customer/mod.xml</code></li>
</ul>
<p><strong>Module DO file</strong></p>
<ul>
<li><code>modules/customer/do/CustomerDO.xml</code></li>
</ul>
<p><strong>Module Form file</strong></p>
<ul>
<li><code>modules/customer/form/CustomerListForm.xml</code></li>
<li><code>modules/customer/form/CustomerDetailForm.xml</code></li>
<li><code>modules/customer/form/CustomerEditForm.xml</code></li>
<li><code>modules/customer/form/CustomerNewForm.xml</code></li>
<li><code>modules/customer/form/CustomerCopyForm.xml</code></li>
</ul>
<p><strong>Module View file</strong></p>
<ul>
<li><code>modules/customer/view/CustomerListView.xml</code></li>
</ul>
<p><strong>Module Widget files</strong></p>
<ul>
<li><code>modules/customer/widget/DashboardForm.xml</code></li>
<li><code>modules/customer/widget/LeftMenu.xml</code></li>
</ul>
<p><strong>Module Template files</strong></p>
<ul>
<li><code>modules/customer/template/detail.tpl</code></li>
<li><code>modules/customer/template/detail_elementset.tpl</code></li>
<li><code>modules/customer/template/grid.tpl</code></li>
<li><code>modules/customer/template/view.tpl</code></li>
</ul>
<p>Next we load the newly created module with the <code>load_module</code> command.</p>
<pre>/dev/cubi/bin/tools/php$ <strong>load_module.php customer</strong>
Start loading customer module ...
--------------------------------------------------------
[2013-01-26T17:57:16+08:00] Loading module customer
[2013-01-26T17:57:16+08:00] Install Module customer
[2013-01-26T17:57:16+08:00] Install Module ACL.
[2013-01-26T17:57:16+08:00] Install Module Menu.
[2013-01-26T17:57:16+08:00] Install Module Widget.
[2013-01-26T17:57:16+08:00] Install Module Resource.
[2013-01-26T17:57:16+08:00] Install Module Change Logs.
[2013-01-26T17:57:16+08:00] Copy resource files to /cubi/resources folder.
[2013-01-26T17:57:16+08:00] customer is loaded.

Give admin to access all actions of module 'customer'
--------------------------------------------------------
End loading customer module</pre>
<p>Let’s test the module. If you are already logged in to Cubi, log out and log back in again. You should see a new tab named “Customer” appearing in the header section. Click the tab to enter the Customer Dashboard page, then click the Customer Manage link to enter the customer management page. Now we&#8217;re able to create, update, search, and delete customers.</p>
<h2>Under the Hood</h2>
<p>You may wonder without any programming, how does Openbiz Cubi make everything work? In the previous steps, <code>gen_meta</code> created XML files under the customer module folder. Cubi then knows how to interpret these files. Let’s visit the module description file <code>mod.xml</code> first.</p>
<h3>Module Description File</h3>
<p>We created the customer module with <code>mod.xml</code> under the <code>modules/customer</code> directory.</p>
<pre class="brush: xml; title: ; notranslate">&lt;?xml version=&quot;1.0&quot; standalone=&quot;no&quot;?&gt;
&lt;Module Name=&quot;customer&quot; Description=&quot;customer module&quot; Version=&quot;0.1.0&quot; OpenbizVersion=&quot;3.0&quot;&gt;
 &lt;ACL&gt;
  &lt;Resource Name=&quot;customer&quot;&gt;
   &lt;Action Name=&quot;Access&quot; Description=&quot;Access Customer Module Dashboard&quot;/&gt;
  &lt;/Resource&gt;
  &lt;Resource Name=&quot;customer&quot;&gt;
   &lt;Action Name=&quot;Access&quot; Description=&quot;Access Customer&quot;/&gt;
   &lt;Action Name=&quot;Manage&quot; Description=&quot;Manage Customer&quot;/&gt;
  &lt;/Resource&gt;
 &lt;/ACL&gt;
 &lt;Menu&gt;
  &lt;MenuItem Name=&quot;CustomerTop&quot; Title=&quot;Customer&quot; Description=&quot;Customer Description&quot; URL=&quot;/customer/dashboard&quot; Parent=&quot;&quot; Order=&quot;10&quot;&gt;
   &lt;MenuItem Name=&quot;Customer&quot; Title=&quot;Customer&quot; Description=&quot;Customer description&quot; URL=&quot;&quot; Order=&quot;10&quot;&gt;
    &lt;MenuItem Name=&quot;Customer.List&quot; Title=&quot;Customer Manage&quot; Description=&quot;&quot;  URL=&quot;/customer/customer_list&quot; Order=&quot;10&quot;/&gt;
   &lt;/MenuItem&gt;  
  &lt;/MenuItem&gt;  
 &lt;/Menu&gt;
 &lt;Dependency&gt;
  &lt;Module Name=&quot;system&quot;/&gt;
 &lt;/Dependency&gt;
&lt;/Module&gt;</pre>
<p><code>mod.xml</code> contains 3 sections:</p>
<ul>
<li>Access control – the <code>ACL</code> section defines the resources and their actions. These definitions are used to control permissions for given roles.</li>
<li>Menu – the <code>Menu</code> section defines the page links in the navigation system (application tabs, breadcrumb, and menus).</li>
<li>Dependencies – the <code>Dependency</code> section defines modules that the current module depends on. The depended modules should be installed first.</li>
</ul>
<p>Usually each module includes its own data models and presentation XML files. The framework has a metadata engine that can then understand the XML and load the data and UI objects on the fly. The framework mainly work with two types of metadata objects:</p>
<ul>
<li>Data objects &#8211; Cubi maps physical data stores (such as a database table) to logic objects.</li>
<li>Form and view objects – Form objects describe how to present data objects&#8217; data on a block in a page, while view objects define a container of Form objects. In a browser, a view is the same as a web page.</li>
</ul>
<h3>Data Object</h3>
<p>Now let’s take a look at the data object XML in <code>modules/customer/do/CustomerDO.xml</code>:</p>
<pre class="brush: xml; title: ; notranslate">&lt;?xml version=&quot;1.0&quot; standalone=&quot;no&quot;?&gt;
&lt;BizDataObj Name=&quot;CustomerDO&quot; Description=&quot;&quot; Class=&quot;BizDataObj&quot; DBName=&quot;Default&quot; Table=&quot;customer&quot; SearchRule=&quot;&quot; SortRule=&quot;&quot; OtherSQLRule=&quot;&quot; Uniqueness=&quot;&quot; Stateless=&quot;N&quot; IdGeneration=&quot;Identity&quot; CacheLifeTime=&quot;0&quot; CreateCondition=&quot;customer.Manage&quot; UpdateCondition=&quot;customer.Manage&quot; DeleteCondition=&quot;customer.Manage&quot;&gt;
 &lt;BizFieldList&gt;
  &lt;BizField Name=&quot;Id&quot; Column=&quot;id&quot; Type=&quot;Number&quot;/&gt;
  &lt;BizField Name=&quot;name&quot; Column=&quot;name&quot; Length=&quot;64&quot; Required=&quot;Y&quot; Type=&quot;Text&quot;/&gt;
  &lt;BizField Name=&quot;description&quot; Column=&quot;description&quot; Length=&quot;255&quot; Required=&quot;N&quot; Type=&quot;Text&quot;/&gt;
  &lt;BizField Name=&quot;address&quot; Column=&quot;address&quot; Length=&quot;255&quot; Required=&quot;N&quot; Type=&quot;Text&quot;/&gt;
  &lt;BizField Name=&quot;phone&quot; Column=&quot;phone&quot; Length=&quot;20&quot; Required=&quot;N&quot; Type=&quot;Text&quot;/&gt;
  &lt;BizField Name=&quot;fax&quot; Column=&quot;fax&quot; Length=&quot;20&quot;   Required=&quot;N&quot; Type=&quot;Text&quot;/&gt;
  &lt;BizField Name=&quot;status&quot; Column=&quot;status&quot;    Required=&quot;N&quot; Type=&quot;Number&quot;/&gt;
  &lt;BizField Name=&quot;create_by&quot; Column=&quot;create_by&quot; Type=&quot;Number&quot; ValueOnCreate=&quot;{@profile:Id}&quot;/&gt;
  &lt;BizField Name=&quot;create_time&quot; Column=&quot;create_time&quot;  Type=&quot;Datetime&quot; ValueOnCreate=&quot;{date('Y-m-d H:i:s')}&quot;/&gt;
  &lt;BizField Name=&quot;update_by&quot; Column=&quot;update_by&quot; Type=&quot;Number&quot; ValueOnCreate=&quot;{@profile:Id}&quot; ValueOnUpdate=&quot;{@profile:Id}&quot;/&gt;		
  &lt;BizField Name=&quot;update_time&quot; Column=&quot;update_time&quot; Type=&quot;Datetime&quot; ValueOnCreate=&quot;{date('Y-m-d H:i:s')}&quot; ValueOnUpdate=&quot;{date('Y-m-d H:i:s')}&quot;/&gt;
 &lt;/BizFieldList&gt;
 &lt;TableJoins&gt;
 &lt;/TableJoins&gt;
 &lt;ObjReferences&gt;
 &lt;/ObjReferences&gt;
&lt;/BizDataObj&gt;</pre>
<p>The XML defines a mapping between the <code>customer</code> table to the <code>CustomerDO</code> object. It also defines certain rules on the objects as well as validation, type, and value of each field.</p>
<h3>Form Object</h3>
<p>Let’s also take a look at the form object XML in <code>modules/customer/form/CustomerListForm.xml</code>.</p>
<pre class="brush: xml; title: ; notranslate">&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;EasyForm Name=&quot;CustomerListForm&quot; Class=&quot;EasyForm&quot; FormType=&quot;List&quot; jsClass=&quot;jbForm&quot; Title=&quot;Customer Management&quot; Description=&quot;&quot; BizDataObj=&quot;customer.do.CustomerDO&quot; PageSize=&quot;10&quot; DefaultForm=&quot;Y&quot; TemplateEngine=&quot;Smarty&quot; TemplateFile=&quot;grid.tpl&quot; Access=&quot;customer.Access&quot;&gt;
 &lt;DataPanel&gt;
  &lt;Element Name=&quot;row_selections&quot; Class=&quot;RowCheckbox&quot; Label=&quot;&quot; FieldName=&quot;Id&quot;/&gt;
  &lt;Element Name=&quot;fld_Id&quot; Class=&quot;ColumnText&quot; FieldName=&quot;Id&quot; Label=&quot;Id&quot; Sortable=&quot;Y&quot;/&gt;
  &lt;Element Name=&quot;fld_name&quot; Class=&quot;ColumnText&quot; FieldName=&quot;name&quot; Label=&quot;Name&quot; DefaultValue=&quot;New Customer&quot; Sortable=&quot;Y&quot; Link=&quot;javascript:&quot;&gt;
  &lt;EventHandler Name=&quot;fld_name_onclick&quot; Event=&quot;onclick&quot; Function=&quot;SwitchForm(customer.form.CustomerDetailForm,{@:Elem[fld_Id].Value})&quot;   /&gt;
 &lt;/Element&gt;
 &lt;Element Name=&quot;fld_description&quot; Class=&quot;ColumnText&quot; FieldName=&quot;description&quot; Label=&quot;Description&quot;  Sortable=&quot;Y&quot;/&gt;
  &lt;Element Name=&quot;fld_address&quot; Class=&quot;ColumnText&quot; FieldName=&quot;address&quot; Label=&quot;Address&quot;  Sortable=&quot;Y&quot;/&gt;
  &lt;Element Name=&quot;fld_phone&quot; Class=&quot;ColumnText&quot; FieldName=&quot;phone&quot; Label=&quot;Phone&quot; Sortable=&quot;Y&quot;/&gt;
  &lt;Element Name=&quot;fld_fax&quot; Class=&quot;ColumnText&quot; FieldName=&quot;fax&quot; Label=&quot;Fax&quot; Sortable=&quot;Y&quot;/&gt;
  &lt;Element Name=&quot;fld_status&quot; Class=&quot;ColumnText&quot; FieldName=&quot;status&quot; Label=&quot;Status&quot; Sortable=&quot;Y&quot;/&gt;
 &lt;/DataPanel&gt;
 &lt;ActionPanel&gt;
...
  &lt;Element Name=&quot;btn_delete&quot; Class=&quot;Button&quot; Text=&quot;Delete&quot; CssClass=&quot;button_gray_m&quot; Access=&quot;customer.Manage&quot;&gt;
   &lt;EventHandler Name=&quot;del_onclick&quot; Event=&quot;onclick&quot; EventLogMsg=&quot;&quot; Function=&quot;DeleteRecord()&quot; ShortcutKey=&quot;Ctrl+Delete&quot; ContextMenu=&quot;Delete&quot;/&gt;
  &lt;/Element&gt;
...
 &lt;/ActionPanel&gt;
 &lt;NavPane&gt;
...
 &lt;/NavPanel&gt;
 &lt;SearchPane&gt;
...
 &lt;/SearchPanel&gt;
&lt;/EasyForm&gt;</pre>
<p>The XML maps fields from data objects to UI elements. It also defines panels for the logical layout of elements. For each UI element, interaction behavior can be described within its <code>EventHandler</code> section.</p>
<h3>Customize Objects</h3>
<p>Each <code>Metadata</code> element comes with a <code>Class</code> attribute. In the metadata generated by <code>gen_meta</code>, the attribute is set to a core framework class (<code>BizDataObj</code> for data objects, <code>EasyForm</code> for form objects). Developers can simply replace this to implement special business logic. For example, to add special logic for deleting a customer record, you can create the file <code>/modules/customer/form/CustomerForm.php</code>, and set the <code>Metadata</code> element&#8217;s <code>Class</code> attribute to it. The PHP class might look like:</p>
<pre class="brush: php; title: ; notranslate">&lt;?php
class CustomerForm extends EasyForm
{
    public function deleteRecord($id = null) {
        // add your logic here
        Parent::deleteRecord($id); // call parent deleteRecord method
    }
}</pre>
<h3>The Cubi Execution Flow</h3>
<p>So what happens when the <em>http://host/cubi/index.php/customer/customer_list</em> is called in the browser?</p>
<ol>
<li><code>index.php</code> calls <code>_forward.php</code> to parse the URL. It understands that <em>/customer/customer_list</em> points to <code>cubi/modules/customer/view/CustomerListView.xml</code> based on Cubi&#8217;s URL naming convention.</li>
<li>The render method of the view is invoked.</li>
<li>The render method calls the render method of its included form (<code>cubi/modules/customer/form/CustomerListForm.xml</code>).</li>
<li>The render method of the form calls its data object&#8217;s data query methods.</li>
<li>The query methods prepare the SQL and executes it against the database.</li>
<li>The form uses the returned dataset from the DO to generate HTML with its template.</li>
<li>The view uses the output of the forms to generate HTML with its template.</li>
<li>The server sends the HTML output to browser.</li>
</ol>
<p>Once a view is loaded in the browser, most user interactions happen on forms through Ajax (no page reload). The diagram below shows how the Ajax call works:</p>
<p><img src="http://cdn.phpmaster.com/files/2013/05/cubi-2-1.png" alt="cubi-2-1" width="411" height="386" class="aligncenter size-full wp-image-5711" style="float:none !important; margin-left:auto; margin-right:auto;"/></p>
<h2>Conclusion</h2>
<p>In the series we&#8217;ve learned how to install Cubi, set up the system, and create a module. You may also find that the XML metadata file can be easier to learn and maintain than programming code. I hope you’ve enjoyed the series and wish you luck with your very own Openbiz Cubi powered business applications.</p>
<p><small>Image via <a title="Royalty Free Stock Photos at Fotolia.com" href="http://us.fotolia.com/?utm_source=sitepoint&amp;utm_medium=website_link&amp;utm=campaign=sitepoint" target="_blank">Fotolia</a></small></p>
<img src="http://feeds.feedburner.com/~r/PHPMaster_feed/~4/so3gaTtZ6-I" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://phpmaster.com/openbiz-cubi-a-robust-php-application-framework-2/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
	
		<series:name><![CDATA[Openbiz Cubi: A Robust PHP Application Framework]]></series:name>
	<feedburner:origLink>http://phpmaster.com/openbiz-cubi-a-robust-php-application-framework-2/</feedburner:origLink></item>
		<item>
		<title>Understanding HTTP Digest Access Authentication</title>
		<link>http://feedproxy.google.com/~r/PHPMaster_feed/~3/AkCYh9HaoPk/</link>
		<comments>http://phpmaster.com/understanding-http-digest-access-authentication/#comments</comments>
		<pubDate>Mon, 20 May 2013 14:30:17 +0000</pubDate>
		<dc:creator>Sean Hudgston</dc:creator>
				<category><![CDATA[Advanced]]></category>
		<category><![CDATA[PHP Tutorials]]></category>

		<guid isPermaLink="false">http://phpmaster.com/?p=5766</guid>
		<description><![CDATA[SSL is the most modern and secure method of sending user authentication data over the public Internet. But if SSL is not available, you should turn to HTTP's Digest Access Authentication over it's Basic Authentication. Digest Access improves on Basic by sending password information as an MD5-hash so it's harder to reverse engineer than the plain text/Base64 encoding. This article discussed Digest Access, including the security features that update the method's original RFC.]]></description>
				<content:encoded><![CDATA[<p>Digest Access Authentication is one method that a client and server can use to exchange credentials over HTTP. This method uses a combination of the password and other bits of information to create an MD5 hash which is then sent to the server to authenticate. Sending a hash avoids the problems with sending a password in clear text, a shortfall of Basic Access Authentication.</p>
<p>Digest Access was originally defined in <a href="http://tools.ietf.org/html/rfc2069" title="RFC 2069 - An Extension to HTTP: Digest Access Authentication" target="_blank">RFC 2069</a>, and optional security enhancements were later added in <a href="http://tools.ietf.org/html/rfc2617" title="RFC 2069 - HTTP Authentication: Basic and Digest Access Authentication" target="_blank">RFC 2617</a> which should be considered the current standard if you wish to implement this method yourself. We&#8217;ll have a look at both in this article.</p>
<h2>The Problem with Basic Access Authentication</h2>
<p>First, lets look a Basic Access Authentication. With your browser, you request some sort of object that requires you to authenticate yourself. If the browser hasn&#8217;t cached credentials you&#8217;ve already provided, you&#8217;ll be met with a “HTTP 401 Not Authorized” response which includes the following header:</p>
<pre>WWW-Authenticate: Basic realm="example.com"</pre>
<p>The client/browser is then expected to respond with the appropriate credentials in order to be allowed access.</p>
<p>The username and password are concatenated together, like “admin:p@ssw0rd”, This string is then Base64 encoded. The encoded string (YWRtaW46cEBzc3cwcmQ=) is used in an Authorization header which is sent back to the server.</p>
<pre>Authorization: Basic YWRtaW46cEBzc3cwcmQ=</pre>
<p>When the server receives this request, it notices the Authorization header and applies the steps in reverse (decode and split the resulting string) to get the original username and password. The process can then do whatever lookup/verification is necessary with the credentials.</p>
<p>The major problem here is that Base64 is a data transfer scheme; it&#8217;s not a hashing or encryption scheme. It may as well be clear text. Digest Access Authentication tries to improve upon this by sending the password as a hashed value, which is much harder (not impossible) to reverse engineer a clear text value from.</p>
<h2>Working with Digest Access Authentication</h2>
<p>When working with Digest Access Authentication, it&#8217;s the server who must make the first move when it discovers a client is trying to access a restricted area. There are a few values the server needs to provide as part of the WWW-Authenticate header that the client needs.</p>
<p>The server generates a value, referred to as <em>nonce</em>, which should be unique for each request.<br />
It&#8217;s recommended this value be either Base64 or hexadecimal, specifically because it will be enclosed in double quotes and we want to ensure there are no double quotes in the string. The nonce will be used by the client to generate a hash to send back to the server.</p>
<p>In PHP, applying <code>md5()</code> to a unique string is generally sufficient.</p>
<pre class="brush: php; title: ; notranslate">&lt;?php
$nonce = md5(uniqid());</pre>
<p>The next value needed by the client is <em>opaque</em>. This is another unique string generated by the server and is expected to be sent and returned by the client unaltered.</p>
<pre class="brush: php; title: ; notranslate">&lt;?php
$opaque = md5(uniqid());</pre>
<p>The last value, <em>realm</em>, is just a string to display to users so they know which username and password they should provide. It&#8217;s also used by the client to generate a hash to send back to the server.</p>
<pre class="brush: php; title: ; notranslate">&lt;?php
$realm = 'Authorized users of example.com';</pre>
<p>All of these values are used to compose the WWW-Authenticate directive and send as a response to the client.</p>
<pre class="brush: php; title: ; notranslate">&lt;?php
if (empty($_SERVER['PHP_AUTH_DIGEST']) {
    header('HTTP/1.1 401 Unauthorized');
    header(sprintf('WWW-Authenticate: Digest realm=&quot;%s&quot;, nonce=&quot;%s&quot;, opaque=&quot;%s&quot;', $realm, $nonce, $opaque));
    header('Content-Type: text/html');
    echo '&lt;p&gt;You need to authenticate.&lt;/p&gt;';
    exit;
}</pre>
<p>When the client receives this response, it has to compute a return hash. It does so by concatenating the username, realm, and password and hashing the result with MD5 as follows:</p>
<ol>
<li>Compute <code>A1</code> as <code>MD5("<em>username</em>:<em>realm</em>:<em>password</em>")</code>.</li>
<li>Compute <code>A2</code> as <code>MD5("<em>requestMethod</em>:<em>requestURI</em>")</code>.
<li>Compute the final hash, know as “response”, as <code>MD5("A1:<em>nonce</em>:A2")</code>.</li>
</ol>
<p>The client sends the response back to the server in an Authorization header and includes the username, realm, nonce, opaque, uri, and the computed response.</p>
<pre>Authorization: Digest username="%s", realm="%s", nonce="%s", opaque="%s", uri="%s", response="%s"'</pre>
<p>Note that realm, nonce, and opaque are all returned to the server unchanged.</p>
<p>When the server receives the response, the same steps are taken to compute the server’s version of the hash. If the computed hash and the received response hash values match, then the request is considered authorized. It looks something like this:</p>
<pre class="brush: php; title: ; notranslate">&lt;?php
$A1 = md5(&quot;$username:$realm:$password&quot;);
$A2 = md5($_SERVER['REQUEST_METHOD'] . &quot;:$uri&quot;);
$response = md5(&quot;$A1:$nonce:$A2&quot;);</pre>
<p>Of course, the user&#8217;s password is never passed to the server. To perform authentication look ups from a database then, the value of A1 can be stored. Keep in mind however the stored hash becomes invalid if you ever change your realm.</p>
<h2>Improving on the Original Digest Access Spec</h2>
<p>Now that you&#8217;re familiar with the workings of Digest Access Authentication from RFC 2069, let&#8217;s turn our attention to some of the enhancements that were added in 2617: qop, nc, and cnonce.</p>
<p><em>qop</em>, or quality of protection, is specified in the WWW-Authenticate header and can have a value of “auth” or “auth-int”. When no qop directive is found or when it is set to “auth”, Digest Access is used for client authentication only – the default mode which you&#8217;ve seen so far.  When set to “auth-int”, an attempt is made to provide some level of integrity protection of the response as well and the client must also include the request body as part of the message digest. This allows the server to determine whether the request has been adulterated in transfer between the indented client and intended server.</p>
<p>The client nonce, or <em>cnonce</em>, is similar to nonce but is generated by the client.  The cnonce figures into the response digest computed by the client and its original value is passed along to the server so that it can be used there to compare digests.  This provides some response integrity and mutual authentication, in that both the client and server have a way to prove they know a shared secret. When the qop directive is sent by the server, the client must include a cnonce value. </p>
<p>The nonce count, <em>nc</em>, is a hexadecimal count of the number of requests that the client has sent with a given nonce value. This way, the server can guard against replay attacks.</p>
<p>With the enhancements, the computation of A2 and the response goes something like this:</p>
<pre class="brush: php; title: ; notranslate">&lt;?php
if ($qop == 'auth-int') {
    $A2 = md5($_SERVER['REQUEST_METHOD'] . &quot;:$uri:&quot; . md5($respBody));
}
else {
    $A2 = md5($_SERVER['REQUEST_METHOD'] . &quot;:$uri&quot;);
}
$response = md5(&quot;$A1:$nonce:$nc:$cnonce:$qop:$A2&quot;);</pre>
<h2>Strengths and Weaknesses of Digest Access Authentication</h2>
<p>Digest Access has some advantages over Basic Authentication, since Basic Authentication uses a clear-text exchange of username and passwords, which is almost the same as telling the world what your password is. Digest Access passes a hashed value and not the password itself, so it&#8217;s much more secure than Basic Auth. The server nonce, which should be unique per request, will drastically change the computed hash on each new request, and the nc value provided by RFC 2617 is helpful at preventing replay attacks, whereby a malicious individual is able to intercept your request data and “replay” or repeat it as his own request. </p>
<p>There are a few weaknesses with Digest Authentication as well. When RFC 2617 replaced the original specification, the enhancements that were added to provide extra security measures between the client and server were made purely optional, and Digest Authentication will proceed in its original RFC 2069 form when not implemented.</p>
<p>Another problem is MD5 is not a strong hashing algorithm. All it takes is time and CPU to brute force the original value back to life. Bcrypt is preferable as it is more resilient against brute force attacks. There&#8217;s also no way for a server to verify the identity of the requesting client when using Digest Access Authentication. This opens the possibility for man in the middle attacks, where a client can be led to believe a given server is really who he thinks it is, but ends up sending his login credentials to an unknown entity.</p>
<p>Your best bet when dealing with authentication is to use SSL and encrypt passwords using Bcrypt. You can use Basic Authentication or a home brewed authentication mechanism over SSL, but for situations where SSL is not possible for whatever reason, Digest Access is better than simple Basic Authentication and sending passwords in plain text over the public Internet.</p>
<p>There&#8217;s a simple example of RFC-2069 HTTP Digest Access available on the <a href="https://github.com/phpmasterdotcom/UnderstandingHTTPDigest" title="phpmasterdotcom/UnderstandingHTTPDigest - GitHub" target="_blank">PHPMaster GitHub page</a> to accompany this article. If you&#8217;re the type of person who likes to explore and tinker, feel free to clone it. A good place to start your exercise is to make the necessary modifications to work with accounts stored in a database instead of the hard-coded credentials in the script (remember, you&#8217;ll need to calculate and store A1 as the user&#8217;s password hash for later lookup at login), and then enhance it with RFC-2617 features. Afterwards, you&#8217;ll have a pretty solid understanding of HTTP Digest Access Authentication.</p>
<h2>Summary</h2>
<p>By now you should have an idea of what your available HTTP authentication methods are. </p>
<p>Basic Authentication is the easiest to implement and also the least secure.  Usernames and passwords are encoded in Base64 but effectively sent to the server in plain text.</p>
<p>Digest Authentication improves on the Basic method by sending authentication data through MD5.  While MD5 is still not a strong password encryption algorithm, it is much harder to decode than the plain text/Base64 method of Basic Authentication.  In its original form, there were still problems of man in the middle attacks and not being able to confirm server identity, but these weaknesses have been improved in later revisions to the RFC.</p>
<p>SSL is the most modern and secure method of sending user authentication data over the public Internet. But when SSL is not available, please use Digest over Basic authentication.</p>
<p><small>Image via <a title="Royalty Free Stock Photos at Fotolia.com" href="http://us.fotolia.com/?utm_source=sitepoint&amp;utm_medium=website_link&amp;utm=campaign=sitepoint" target="_blank">Fotolia</a></small></p>
<img src="http://feeds.feedburner.com/~r/PHPMaster_feed/~4/AkCYh9HaoPk" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://phpmaster.com/understanding-http-digest-access-authentication/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		<feedburner:origLink>http://phpmaster.com/understanding-http-digest-access-authentication/</feedburner:origLink></item>
		<item>
		<title>Openbiz Cubi: A Robust PHP Application Framework, Part 1</title>
		<link>http://feedproxy.google.com/~r/PHPMaster_feed/~3/-B5b98v2sfs/</link>
		<comments>http://phpmaster.com/openbiz-cubi-a-robust-php-application-framework-1/#comments</comments>
		<pubDate>Thu, 16 May 2013 14:30:45 +0000</pubDate>
		<dc:creator>Rocky Swen</dc:creator>
				<category><![CDATA[Intermediate]]></category>
		<category><![CDATA[PHP Tutorials]]></category>
		<category><![CDATA[Frameworks]]></category>

		<guid isPermaLink="false">http://phpmaster.com/?p=5703</guid>
		<description><![CDATA[Openbiz Cubi is a robust PHP application framework giving developers the ability to create business applications with minimal effort. In this two-part series you'll learn the concepts and steps necessary to create your own business web applications with Cubi. This part looks at the challenges web developers face and how Cubi can help.]]></description>
				<content:encoded><![CDATA[<p>The web has been a standard platform for both consumer-facing and business-facing applications for more than 10 years. The enormous amount of open source projects, commercial tools, and frameworks make fast web development possible.</p>
<p>Openbiz Cubi is a robust PHP application framework giving developers the ability to create business applications with minimal effort. In this two-part series I&#8217;ll explain the concepts and steps necessary to create your own business web applications with Cubi. We&#8217;ll look first at the challenges web developers face and how Openbiz Cubi can help, and then how to install Cubi. In part 2 we&#8217;ll see how to create our own modules.</p>
<h2>Openbiz Cubi Features</h2>
<p>Even with many choices for a web development framework, application development is still a very challenging job.</p>
<p>A good framework can help developers code with good programming practices such MVC and ORM, although to build a real world application we sometimes have to spend time writing code beyond the capability of the framework.</p>
<ul>
<li>Learn the framework and code with it. After creating a “Hello World” app with the framework, developers still have a steep learning curve to build the first prototyped application.</li>
<li>Implement common features like user registration, login, password reset, etc.</li>
<li>Provide permission control for users. Because of the complexity of generalizing access control, permission logic is often hardcoded in the software.</li>
<li>Make a professional UI. Fine-tuning HTML, CSS, and JavaScript is time-consuming, especially to please all major browsers.</li>
</ul>
<p>All the above tasks are necessary but not the highlighted features of the application. Spending too much time on them brings frustration to both clients and the development team.</p>
<p>Openbiz Cubi is a mature platform, mainly for the fast development of business applications. It was designed to relieve the pain of such application development by providing:</p>
<ul>
<li>An XML-based coding scheme. Developers use intuitive XML to describe the data objects, pages and forms, as well as user interaction.</li>
<li>A modular platform that has many common component built-in. Developers make their own modules and load them in the platform.</li>
<li>A default professional-looking UI with multi-theme support.</li>
<li>Flexible permission control options, from simple to sophisticated.</li>
</ul>
<p>To learn more about Cubi, be sure to visit the project site <a href="http://code.google.com/openbiz-cubi" title="" target="_blank">code.google.com/openbiz-cubi</a> and official website <a href="http://www.openbiz.me" title="" target="_blank">www.openbiz.me</a>.</p>
<h2>Installing Openbiz Cubi</h2>
<p>To install Openbiz Cubi, you need to download either the source code or Windows installer from <a href="http://code.google.com/p/openbiz-cubi/downloads/list" title="" target="_blank">code.google.com/p/openbiz-cubi/downloads/list</a>, or you can get the latest source code from the <a href="http://code.google.com/p/openbiz-cubi/source/checkout" title="" target="_blank">Openbiz Cubi SVN server</a>.</p>
<p>When you choose to download the source ZIP archive or get the source from SVN, you can follow the steps below to install it:</p>
<ol>
<li>Prepare the LAMP stack. Openbiz Cubi can be run on Unix, Windows, and Mac servers. The runtime environment should include:</li>
<ul>
<li>Web server &#8211; Apache, IIS, etc.</li>
<li>Database server &#8211; MySQL, MSSQL, Oracle, PgSQL, and databases supported by Zend_DB</li>
<li>PHP 5.2 and above with mysql, PDO, and mcrypt extensions</li>
</ul>
<li>In your web server&#8217;s web directory, create a folder named <code>cubi</code>.</li>
<li>Unzip the Cubi ZIP file to the directory (or check out the source from SVN under this directory).</li>
</ol>
<p>If you use Windows as your development environment, you can install Cubi with its Windows Installer. The installer:</p>
<ul>
<li>Installs Apache 2.4, PHP 5.4 and MySQL 5.3. After installation is completed, you can find Apache and MySQL in the System Services list.</li>
<li>Installs the Openbiz Cubi platform and business applications. You can choose to unselect the options of installing business applications which are not released under open source.</li>
<li>Adds desktop icons and start menu items.</li>
</ul>
<p>After the code is installed to the web server&#8217;s directory, you can launch Cubi&#8217;s web installation wizard in a browser to set up the database and load modules. Run the installation wizard by launching <em>http://host/cubi/install</em> in your browser.</p>
<p><img src="http://cdn.phpmaster.com/files/2013/05/cubi-1-1.png" alt="cubi-1-1" width="600" class="aligncenter size-full wp-image-5704" style="float:none !important; margin-left: auto; margin-right: auto;"/></p>
<p>Click the Start Now button and follow the steps until you see Installation Completed page. Then you&#8217;ll be ready to test drive Cubi.</p>
<p><img src="http://cdn.phpmaster.com/files/2013/05/cubi-1-2.png" alt="cubi-1-2" width="600" class="aligncenter size-full wp-image-5705" style="float:none !important; margin-left: auto; margin-right: auto;"/></p>
<h2>A Quick Tour of Openbiz Cubi</h2>
<p>After you log in to Cubi as <em>admin</em>, you&#8217;ll see the Administration dashboard. You may see other tabs as well, like “Contacts” and “Calendar”. </p>
<p>Cubi is made of modules. All modules are under the <code>cubi/modules</code> directory. Of the many built-in modules, the following are the most important; they are core modules that are often used by other modules:</p>
<ul>
<li>System module &#8211; provides the ability for system administrators to manage users, roles, modules, groups and permissions.</li>
<li>Menu module &#8211; provides support for page navigation by menus, tabs, and breadcumbs.</li>
<li>User module &#8211; provides functions for users to register, sign in, and reset passwords.</li>
<li>MyAccount module &#8211; provides My Account pages where a user can manage his own profile, preferences, activities, and password.</li>
</ul>
<p>Cubi comes with other modules such as Contact, Email, Event Log, Security, Theme, Translation, Attachment, Picture, Chart, Payment, OAuth, Web Service, and more.</p>
<p>A typical Cubi page on the front-end is composed of four sections:</p>
<ul>
<li>Header &#8211; this section contains the logo, My Account link, application tabs, and breadcrumb navigation.</li>
<li>Left Menu &#8211; this section contains navigation menus and other widgets.</li>
<li>Content &#8211; this is the main area users will work in with their data and business logic.</li>
<li>Footer &#8211; the footer may have links about the application provider, copyright, etc.</li>
</ul>
<p><img src="http://cdn.phpmaster.com/files/2013/05/cubi-1-3.png" alt="cubi-1-3" width="600" class="aligncenter size-full wp-image-5706" style="float:none !important; margin-left: auto; margin-right: auto;"/></p>
<h2>Manage Users and Roles</h2>
<p>For the application administrator, one of the most important tasks is to manage users and their permissions to access certain resources. Cubi supports several widely used access control models including Role-based access control (RBAC) and Group-based access control (similar to Unix file permissions). I&#8217;ll briefly discuss how to use RBAC.</p>
<p>A Cubi user account is simply called “user”. A role usually means a type of user. Different roles are permitted to do different things. Cubi comes with three roles: administrator, member, and visitor. A user can be assigned to one or many roles. </p>
<p>An administrator needs to use the Role Management page to allow or deny resources for a given role. When he wants to grant a user certain permissions, he associates the user to a new role that has those permissions.</p>
<p><img src="http://cdn.phpmaster.com/files/2013/05/cubi-1-4.png" alt="cubi-1-4" width="600" class="aligncenter size-full wp-image-5707" style="float:none !important; margin-left: auto; margin-right: auto;"/></p>
<h3>Conclusion</h3>
<p>This is where I&#8217;ll end the first part of the series. So far we&#8217;ve talked about the challenges web developers face and how Openbiz Cubi can help, how to install Cubi, and undertook a brief overview of how Cubi is organized. In the next part I&#8217;ll dig deeper and show you how to create your own module. Stay tuned!</p>
<p><small>Image via <a title="Royalty Free Stock Photos at Fotolia.com" href="http://us.fotolia.com/?utm_source=sitepoint&amp;utm_medium=website_link&amp;utm=campaign=sitepoint" target="_blank">Fotolia</a></small></p>
<img src="http://feeds.feedburner.com/~r/PHPMaster_feed/~4/-B5b98v2sfs" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://phpmaster.com/openbiz-cubi-a-robust-php-application-framework-1/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
	
		<series:name><![CDATA[Openbiz Cubi: A Robust PHP Application Framework]]></series:name>
	<feedburner:origLink>http://phpmaster.com/openbiz-cubi-a-robust-php-application-framework-1/</feedburner:origLink></item>
		<item>
		<title>Safely Deprecating APIs</title>
		<link>http://feedproxy.google.com/~r/PHPMaster_feed/~3/GUwvzke73B8/</link>
		<comments>http://phpmaster.com/safely-deprecating-apis/#comments</comments>
		<pubDate>Tue, 14 May 2013 14:30:38 +0000</pubDate>
		<dc:creator>Mark Wilston</dc:creator>
				<category><![CDATA[Intermediate]]></category>
		<category><![CDATA[PHP Tutorials]]></category>

		<guid isPermaLink="false">http://phpmaster.com/?p=5685</guid>
		<description><![CDATA[Deprecating features before they are done away or transformed gives users who depend on your code time to update their own code. By following the advice in this article, you will find it easier to keep your code fresh and your users won’t have any unhappy surprises.]]></description>
				<content:encoded><![CDATA[<p>Deprecation is a position in the software development lifecycle where a certain feature needs to be removed or avoided because it’s out of date. Deprecated features are not done away with immediately; rather they are retained but raise warning messages that recommend using alternative practices. This gives users time to update their code before the unwanted code is finally removed.</p>
<p>Deprecation can happen for various reasons – perhaps an API is no longer useful and has reached its end-of-life, or the refactoring of code to improve its reusability and testability obsoletes particular methods.</p>
<p>In this article I’ll share with you some key points that you should follow when deprecating APIs so you can continue to grow your code and provide fair warning to those who depend on it.</p>
<h2>Prepare for Refactoring</h2>
<p>Even though it is tedious, make sure you first document your code. This will assist you in better understanding what code is responsible for what functionality and how it functions as a whole. Use a standardized document format so it can be used by your IDE and easily compiled into readable documentation.</p>
<p>Then, to ensure your service or library continues to work after you deprecate parts of its API, test the original code with your unit tests. If the tests fail, you must fix the problems so you can distinguish between failures that were brought by deprecating the API and failures that were already there.</p>
<h2>Employ the Single Responsibility Principle</h2>
<p>Logically organize your code based on the purpose and function of various components, and employ the Single Responsibility Principle (SRP). The principle ensures the methods and classes that perform more than one job are refactored so each has a single task. This increases the reusability and testability of your code. Don’t worry if there are many classes and methods in your API as a result of applying the SRP; reusable and testable code allows deprecating changes to be targeted to a minimal amount of code.</p>
<h2>Communicate with your Users</h2>
<p>Depending on the size of your user base, establishing good communication can be difficult. A good solution is to establish a mailing list to which they can subscribe. The period of time that you can allow users to continue using old methods once you’ve announced the intended changes on the list depends on factors like the importance and why the change is being made.<br />
Depending on your API and the resources available to your project, it might also be beneficial to host a project wiki where developers can share alternative strategies and workarounds to avoid deprecated methods calls.</p>
<p>For libraries, the methods and classes that provide your API should be updated to issue descriptive warning messages that can be logged when they’re used. If you’re providing a web service, define headers that do not affect the current implementation but which allow you to include metadata with the service call. These headers can allow you communicate with your users about service changes.</p>
<h2>Remove the Old Code</h2>
<p>After making the necessary changes, be sure to read through your code carefully to make sure the unneeded, unused, or old code, is safe to remove. Code analysis tools can be helpful as well.</p>
<p>When a suitable deprecation period has passed, you can go ahead and prune the old code. After removing code that is no longer necessary, it is important you perform tests to make sure the system is still functioning properly so as to avoid failures.</p>
<h2>Summary</h2>
<p>Deprecation can improve the internal consistency of a web service or library in the software code, its structure or the user interface. This makes it easier for users to understand how the system works reducing the cost of coming up with a new system.<br />
Refactoring helps to improve the user experience of your API and makes future changes to your code easier to implement. Code becomes more reusable and testable. But the process of refactoring also means some code because unnecessary and should be removed to keep the project clean.</p>
<p>Deprecating features before they are done away or transformed gives users who depend on your code time to update their own code. By following the advice in this article, you will find it easier to keep your code fresh and your users won’t have any unhappy surprises.</p>
<p><small>Image via <a title="Royalty Free Stock Photos at Fotolia.com" href="http://us.fotolia.com/?utm_source=sitepoint&amp;utm_medium=website_link&amp;utm=campaign=sitepoint" target="_blank">Fotolia</a></small></p>
<img src="http://feeds.feedburner.com/~r/PHPMaster_feed/~4/GUwvzke73B8" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://phpmaster.com/safely-deprecating-apis/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://phpmaster.com/safely-deprecating-apis/</feedburner:origLink></item>
		<item>
		<title>MongoDB Indexing, Part 2</title>
		<link>http://feedproxy.google.com/~r/PHPMaster_feed/~3/y_tMwIHveuw/</link>
		<comments>http://phpmaster.com/mongodb-indexing-2/#comments</comments>
		<pubDate>Fri, 10 May 2013 14:30:21 +0000</pubDate>
		<dc:creator>Ashish Trivedi</dc:creator>
				<category><![CDATA[Advanced]]></category>
		<category><![CDATA[PHP Tutorials]]></category>
		<category><![CDATA[Database]]></category>

		<guid isPermaLink="false">http://phpmaster.com/?p=5624</guid>
		<description><![CDATA[A proper understanding of indexing is important since it can improve the performance and throughput of your application. This series on MongoDB indexing concludes with a look at a few small but important concepts, like indexing on sub-documents and embedded fields, covered queries, and index direction.]]></description>
				<content:encoded><![CDATA[<p>In <a href="http://phpmaster.com/mongodb-indexing-1/" title="MongoDB Indexing, Part 1">part 1</a> of this series we had an introduction to indexing in MongoDB. we saw how to create, use, and analyze queries with indexes giving us a good foundation to build on. In this part, we&#8217;ll take a look at a few more small but important concepts, like indexing on sub-documents and embedded fields, covered queries, and index direction.</p>
<p>Of course, this part assumes that you know how to create an index on a and use the <code>explain()</code> method to analyze it. If you don&#8217;t already know how, I suggest you go back and read part one before continuing here.</p>
<p>We used a collection named <code>posts</code> in the last article. For our work here, let’s add a new field <code>location</code> to it to store the location from which the post was made. The field is a sub-document, and stores the city, state, and country of the user as shown below (a sub-document is a field having a document structure):</p>
<pre class="brush: jscript; title: ; notranslate">{
    &quot;_id&quot;: ObjectId(&quot;5146bb52d852470060001f4&quot;),
    &quot;comments&quot;: {
        &quot;0&quot;: &quot;This is the first comment&quot;,
        &quot;1&quot;: &quot;This is the second comment&quot;
    },
    &quot;post_likes&quot;: 40,
    &quot;post_tags&quot;: {
        &quot;0&quot;: &quot;MongoDB&quot;,
        &quot;1&quot;: &quot;Tutorial&quot;,
        &quot;2&quot;: &quot;Indexing&quot;
    },
    &quot;post_text&quot;: &quot;Hello Readers!! This is my post text&quot;,
    &quot;post_type&quot;: &quot;private&quot;,
    &quot;user_name&quot;: &quot;Mark Anthony&quot;,
    &quot;location&quot;: {
        &quot;city&quot;: &quot;Los Angeles&quot;,
        &quot;state&quot;: &quot;California&quot;,
        &quot;country&quot;: &quot;USA&quot;
    }
}</pre>
<h2>Indexing on Sub-documents</h2>
<p>Suppose we want to search posts based on where the user lives. For this, we need to create an index on the sub-document <code>location</code> field, which in turn indexes the sub-fields. Then we&#8217;ll be able to use the index for the following kinds of queries:</p>
<pre class="brush: php; title: ; notranslate">&lt;?php
// query to find posts from the city of Los Angeles
$cursor = $collection-&gt;find(
    array(
        &quot;location&quot; =&gt; &quot;Los Angeles&quot;
    ),
    array()
);

// query to find posts from the state of California
$cursor = $collection-&gt;find(
    array(
        &quot;location&quot; =&gt; &quot;California&quot;
    ),
    array()
);

// query to find posts from the United States
$cursor = $collection-&gt;find(
    array(
        &quot;location&quot; =&gt; &quot;USA&quot;
    ),
    array()
);</pre>
<p>We&#8217;re able to search all of the sub-fields (<code>city</code>, <code>state</code>, and <code>country</code>) in the sub-document using only <code>location</code> as the key. The query looks to see if any of the sub-fields of <code>location</code> meet our search criteria. </p>
<p>It should be noted that, similar to indexing on arrays, separate indexes are created for all the of the sub-fields internally. In this case, three indexes are created as <code>location.city</code>, <code>location.state</code> and <code>location.country</code>, hence such indexes should be used with care since each index occupies space in memory.</p>
<h2>Indexing on Embedded Fields</h2>
<p>It will happen sometimes that we won’t need indexes on all of the fields of a sub-document. If in our application we only want to find posts based on city but not state or country, we can create the index on the embedded field <code>city</code>.</p>
<p><img src="http://cdn.phpmaster.com/files/2013/05/mongo-2-1.png" alt="mongo-2-1" width="714" height="59" class="aligncenter size-full wp-image-5667" style="float: none !important; margin-left:auto; margin-right: auto;"></p>
<p>We can now use this index in queries to find posts based on city:</p>
<pre class="brush: php; title: ; notranslate">&lt;?php
// query to find posts from the city of Los Angeles
$cursor = $collection-&gt;find(
    array(
        &quot;location.city&quot; =&gt; &quot;Los Angeles&quot;
    ),
    array()
);</pre>
<h2>Index Direction (Ascending/Descending)</h2>
<p>We&#8217;ve always provide an index direction (1 or -1) to keys when creating our indexes. I touched on this briefly in part 1, but this is actually an important discussion point I&#8217;d like like to pick up again. If we have one key in the index, direction 1 or -1 doesn’t really matter, but it comes into play when we do sorting or ranged queries with compound indexes.</p>
<p>Suppose we have a compound index with key <code>field1</code> ascending and key <code>field2</code> descending. In this case, the indexing table may look like this:</p>
<p><img src="http://cdn.phpmaster.com/files/2013/05/mongo-2-2.png" alt="mongo-2-2" width="173" height="204" class="aligncenter size-full wp-image-5668" style="float: none !important; margin-left:auto; margin-right: auto;"></p>
<p>A query with sorting on <code>field1</code> ascending and <code>field2</code> ascending will travel rows in this order: 1, 2, 3, 4, 5, 6, 7, 8, 9. A query with <code>field1</code> ascending and <code>field2</code> descending will travel: 3, 2, 1, 6, 5, 4, 9, 8, 7. Such out-of-order jumps in the search tree can end up being costly to query performance.</p>
<p>Of course index structure above is represented as a table just for the purposes of understanding. Remember, MongoDB uses tree structures internally; each element is stored as a node of a tree. The elements closer to each other would be under the same branches, and hence easily approachable. If a query has to retrieve multiple records in a sorted manner, it would be logically correct to place the elements near each other in the tree for faster retrieval in comparison to the case where the query has to jump from one node to another far node to grab the elements.</p>
<p>If you are looking to sort on <code>field1:1,field2:1</code>, then index <code>{field1:1, field2:1}</code> would be faster than <code>{field1:1, field2:-1}</code> or <code>{field1:-1, field2:1}</code>.</p>
<h2>Covered Queries</h2>
<p>As per MongoDB&#8217;s documentation, a covered query is the one in which:</p>
<ul>
<li>all fields used in the query are part of an index used in the query, and</li>
<li>all the fields returned in the results are in the same index</li>
</ul>
<p>Since all the fields are covered in the index itself, MongoDB can match the query condition as well as return the result fields using the same index without looking inside the documents. Since indexes are stored in RAM or sequentially located on disk, such access is a lot faster.</p>
<p>Consider we have a compound index defined on the <code>post_type</code> and <code>user_name</code> fields. This index covers the following query:</p>
<pre class="brush: php; title: ; notranslate">&lt;?php
// query to find posts with type public and get only user_name in result
$cursor = $collection-&gt;find(
    array(
        &quot;post_type&quot; =&gt; &quot;public&quot;,
    ),
    array(
        &quot;user_name&quot; =&gt; 1,
        &quot;_id&quot; =&gt; 0
    )
);</pre>
<p>We&#8217;ve explicitly excluded the <code>_id</code> field from the result to take advantage of the covered query. As you may already know, all queries return the <code>_id</code> field by default. As per the second condition for covered queries, all the fields returned in the result should be included in the index. We don’t have <code>_id</code> in our compound index on <code>post_type</code> and <code>user_name</code>, so we have to exclude this field from the result.</p>
<p>To check if the query is covered, we can look to the <code>indexOnly</code> field in the result of the <code>explain()</code> method. A true value of indicates that ours was a covered query. </p>
<p><img src="http://cdn.phpmaster.com/files/2013/05/mongo-2-3.png" alt="mongo-2-3" width="510" height="84" class="aligncenter size-full wp-image-5669" style="float: none !important; margin-left:auto; margin-right: auto;"></p>
<p>It&#8217;s important to know that an index can’t cover a query if:</p>
<ul>
<li>any of the indexed fields is an array (e.g. <code>post_tags</code>), or</li>
<li>any of the indexed fields are fields in sub-documents (e.g. <code>location.city</code>)</li>
</ul>
<p>Thus, it&#8217;s always a good practice to check your query index usage with <code>explain()</code>.</p>
<h2>Removing Indexes</h2>
<p>To check the current index size for a database, we can use the <code>totalIndexSize()</code> method which returns the index size in bytes.</p>
<p><img src="http://cdn.phpmaster.com/files/2013/05/mongo-2-4.png" alt="mongo-2-4" width="714" height="76" class="aligncenter size-full wp-image-5670" style="float: none !important; margin-left:auto; margin-right: auto;"></p>
<p>We just have to ensure that we have enough RAM available to accommodate indexes as well as the data that MongoDB manages and uses regularly.</p>
<p>To delete an existing index, and thus free up resources, we use the <code>dropIndex()</code> method.</p>
<p><img src="http://cdn.phpmaster.com/files/2013/05/mongo2-5.png" alt="mongo2-5" width="714" height="76" class="aligncenter size-full wp-image-5673" style="float: none !important; margin-left:auto; margin-right: auto;"></p>
<h2>Conclusion</h2>
<p>That’s all for this part and also the series. We&#8217;ve touched on a lot of important topics to get you up to speed with indexing in MongoDB. </p>
<p>Analyzing your indexes to make sure they are doing well is an on-going process as your application grows and your data changes, so if you have any kind questions or comments about the article, feel free to post in the comments below.</p>
<p><small>Image via <a title="Royalty Free Stock Photos at Fotolia.com" href="http://us.fotolia.com/?utm_source=sitepoint&amp;utm_medium=website_link&amp;utm=campaign=sitepoint" target="_blank">Fotolia</a></small></p>
<img src="http://feeds.feedburner.com/~r/PHPMaster_feed/~4/y_tMwIHveuw" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://phpmaster.com/mongodb-indexing-2/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<series:name><![CDATA[MongoDB Indexing]]></series:name>
	<feedburner:origLink>http://phpmaster.com/mongodb-indexing-2/</feedburner:origLink></item>
		<item>
		<title>Maven and PHP</title>
		<link>http://feedproxy.google.com/~r/PHPMaster_feed/~3/dWSSFkDC7vo/</link>
		<comments>http://phpmaster.com/maven-and-php/#comments</comments>
		<pubDate>Wed, 08 May 2013 14:30:40 +0000</pubDate>
		<dc:creator>Octavia Anghel</dc:creator>
				<category><![CDATA[Intermediate]]></category>
		<category><![CDATA[PHP Tutorials]]></category>
		<category><![CDATA[Deployment]]></category>

		<guid isPermaLink="false">http://phpmaster.com/?p=5648</guid>
		<description><![CDATA[Maven for PHP is a capable build automation tool for the PHP platform. Using Maven, the user only needs to provide the configuration for the project, while the configurable plugins do the work of compiling the project, running unit tests, generating API documentation and so on.  Through this article you will gain familiarity with Maven for PHP, and how to install and use the PHP-Maven plugin from the command line and in Eclipse.]]></description>
				<content:encoded><![CDATA[<p>Apache Maven is a build automation tool with the purpose of building, reporting, and creating documentation of projects. It builds projects using a Project Object Model (POM) and a set of plugins shared by all projects using Maven, thus providing a uniform build system. Once you familiarize yourself with how one Maven project builds, you automatically know how all Maven projects build. This saves you an immense amount of time from trying to navigate the build process of many different projects.</p>
<p>Through this article you will gain familiarity with Maven for PHP, and how to install and use the PHP-Maven plugin from the command line and in Eclipse.</p>
<h2>Install Maven</h2>
<p>PHP-Maven uses the power of Maven for building, reporting, and creating documentation of your PHP projects. It adapts the Maven build life cycle to the PHP world while fully supporting PHP 5. PHP-Maven uses <a href="https://github.com/sebastianbergmann/phpunit/" title="sebastianbergmann/phpunit - GitHub" target="_blank">PHPUnit</a> for unit testing and <a href="http://www.phpdoc.org/" title="phpDocumentor 2" target="_blank">phpDocumentor</a> for creating the project documentation.</p>
<p>To install Maven:</p>
<ol>
<li>Download Maven from <a href="http://maven.apache.org/download.cgi" title="Maven - Download Apache Maven" target="_blank">http://maven.apache.org/download.cgi</a>. For this article, the version is 3.0.4.</li>
<li>Unpack the archive wherever you would like to store the binaries, and a folder named <code>apache-maven-&lt;version&gt;</code> will be created.</li>
<li>Add its <code>bin</code> folder to your <code>PATH</code>.</li>
<li>Make sure <code>JAVA_HOME</code> is set to the location of your JDK.</li>
</ol>
<p>After you&#8217;ve completed the above steps, to test whether Maven is installed correctly or not you should run <code>mvn --version</code> at a command prompt.</p>
<p><img src="http://cdn.phpmaster.com/files/2013/05/maven-1.png" alt="maven-1" width="600" height="134" class="aligncenter size-full wp-image-5651" style="float:none !important; margin-left:auto; margin-right:auto;"></p>
<p>Once Maven is successfully installed, go to the <code>settings.xml</code> file (found in <code>~/.m2</code> on Unix/Mac OS X and in <code>C:\Documents and Settings\username\.m2</code> on Windows) and add the PHP for Maven repository. If there is no <code>settings.xml</code> file, you must create it.</p>
<p>Below is a sample <code>settings.xml</code> file:</p>
<pre class="brush: xml; title: ; notranslate">&lt;settings&gt;
 &lt;profiles&gt;
  &lt;profile&gt;
   &lt;id&gt;profile-php-maven&lt;/id&gt;
   &lt;pluginRepositories&gt;
    &lt;pluginRepository&gt;
     &lt;id&gt;release-repo1.php-maven.org&lt;/id&gt;
     &lt;name&gt;PHP-Maven 2 Release Repository&lt;/name&gt;
     &lt;url&gt;http://repos.php-maven.org/releases&lt;/url&gt;
     &lt;releases&gt;
      &lt;enabled&gt;true&lt;/enabled&gt;
     &lt;/releases&gt;
    &lt;/pluginRepository&gt;

    &lt;pluginRepository&gt;
     &lt;id&gt;snapshot-repo1.php-maven.org&lt;/id&gt;
     &lt;name&gt;PHP-Maven 2 Snapshot Repository&lt;/name&gt;
     &lt;url&gt;http://repos.php-maven.org/snapshots&lt;/url&gt;
     &lt;releases&gt;
      &lt;enabled&gt;false&lt;/enabled&gt;
     &lt;/releases&gt;
     &lt;snapshots&gt;
      &lt;enabled&gt;true&lt;/enabled&gt;
     &lt;/snapshots&gt;
    &lt;/pluginRepository&gt;
   &lt;/pluginRepositories&gt;

   &lt;repositories&gt;
    &lt;repository&gt;
     &lt;id&gt;release-repo1.php-maven.org&lt;/id&gt;
     &lt;name&gt;PHP-Maven 2 Release Repository&lt;/name&gt;
     &lt;url&gt;http://repos.php-maven.org/releases&lt;/url&gt;
     &lt;releases&gt;
      &lt;enabled&gt;true&lt;/enabled&gt;
     &lt;/releases&gt;
    &lt;/repository&gt;

    &lt;repository&gt;
     &lt;id&gt;snapshot-repo1.php-maven.org&lt;/id&gt;
     &lt;name&gt;PHP-Maven 2 Snapshot Repository&lt;/name&gt;
     &lt;url&gt;http://repos.php-maven.org/snapshots&lt;/url&gt;
     &lt;releases&gt;
      &lt;enabled&gt;false&lt;/enabled&gt;
     &lt;/releases&gt;
     &lt;snapshots&gt;
      &lt;enabled&gt;true&lt;/enabled&gt;
     &lt;/snapshots&gt;
    &lt;/repository&gt;
   &lt;/repositories&gt;
  &lt;/profile&gt;
 &lt;/profiles&gt;

 &lt;activeProfiles&gt;
  &lt;activeProfile&gt;profile-php-maven&lt;/activeProfile&gt;
 &lt;/activeProfiles&gt;
&lt;/settings&gt;</pre>
<h2>Create Your First Project</h2>
<p>To create a simple project from the command line I’ll use the <a href="http://maven.apache.org/archetype/maven-archetype-plugin/generate-mojo.html" title="archetype:generate" target="_blank">Maven Archetype Plugin</a>. The Archetype Plugin allows a user to create a Maven project from an existing template called an archetype. You can run the Maven Archetype plugin with the <code>mvn archetype:generate</code> command to generate a new project from an archetype, in a folder corresponding to its artifact ID.</p>
<p><img src="http://cdn.phpmaster.com/files/2013/05/maven-2.png" alt="maven-2" width="600" height="89" class="aligncenter size-full wp-image-5652" style="float:none !important; margin-left:auto; margin-right:auto;"></p>
<p>Maven will start downloading all the dependencies needed to your computer. At some point, Maven will ask you to define a value for <code>groupId</code>, <code>artifactId</code>, <code>version</code> and <code>package</code>, as you see here:</p>
<p><img src="http://cdn.phpmaster.com/files/2013/05/maven-3.png" alt="maven-3" width="600" height="386" class="aligncenter size-full wp-image-5653" style="float:none !important; margin-left:auto; margin-right:auto;"></p>
<p>Notice that at the official <a href="http://maven.apache.org/archetype/maven-archetype-plugin/generate-mojo.html" title="archetype:generate" target="_blank">Maven Archetype Plugin page</a> you will find all the available parameters along with their description.</p>
<p>After successfully creating your first project, you should find the following in the corresponding folder, in my case <code>Octavia_project</code>:</p>
<p><img src="http://cdn.phpmaster.com/files/2013/05/maven-4.png" alt="maven-4" width="600" height="184" class="aligncenter size-full wp-image-5654" style="float:none !important; margin-left:auto; margin-right:auto;"></p>
<ul>
<li><code>src/main/php</code> - contains the project&#8217;s source code.</li>
<li><code>src/test/php</code> - contains the project&#8217;s test code.</li>
<li><code>src/site</code> – contains the project’s site descriptor.</li>
<li><code>pom.xml</code> - contains the project&#8217;s POM description.</li>
</ul>
<p>The contents of <code>pom.xml</code> looks like this:</p>
<pre class="brush: xml; title: ; notranslate">&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;project xmlns=&quot;http://maven.apache.org/POM/4.0.0&quot; 
 xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot; 
 xsi:schemaLocation=&quot;http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd&quot;&gt;

 &lt;parent&gt;
  &lt;groupId&gt;org.phpmaven&lt;/groupId&gt;
  &lt;artifactId&gt;php-parent-pom&lt;/artifactId&gt;
  &lt;version&gt;2.0.2&lt;/version&gt;
 &lt;/parent&gt;

 &lt;modelVersion&gt;4.0.0&lt;/modelVersion&gt;
 &lt;groupId&gt;org.phpsample&lt;/groupId&gt;
 &lt;artifactId&gt;Octavia_project&lt;/artifactId&gt;
 &lt;packaging&gt;php&lt;/packaging&gt;
 &lt;version&gt;1.0-SNAPSHOT&lt;/version&gt;
 &lt;build&gt;
  &lt;plugins&gt;
   &lt;plugin&gt;
    &lt;groupId&gt;org.phpmaven&lt;/groupId&gt;
    &lt;artifactId&gt;maven-php-plugin&lt;/artifactId&gt;
    &lt;extensions&gt;true&lt;/extensions&gt;
   &lt;/plugin&gt;

   &lt;plugin&gt;
    &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;
    &lt;artifactId&gt;maven-site-plugin&lt;/artifactId&gt;
    &lt;version&gt;3.0&lt;/version&gt;
    &lt;configuration&gt;
     &lt;reportPlugins&gt;
      &lt;plugin&gt;
       &lt;groupId&gt;org.phpmaven&lt;/groupId&gt;
       &lt;artifactId&gt;maven-php-plugin&lt;/artifactId&gt;
       &lt;reportSets&gt;
        &lt;reportSet&gt;
         &lt;reports&gt;
          &lt;report&gt;phpdocumentor&lt;/report&gt;
          &lt;report&gt;phpunit-coverage&lt;/report&gt;
          &lt;report&gt;phpunit&lt;/report&gt;  
         &lt;/reports&gt;
        &lt;/reportSet&gt;
       &lt;/reportSets&gt;
      &lt;/plugin&gt;
     &lt;/reportPlugins&gt;
    &lt;/configuration&gt;
   &lt;/plugin&gt;
  &lt;/plugins&gt;
 &lt;/build&gt;

 &lt;dependencies&gt;
  &lt;!--  phpUnit for PHP 5 --&gt;
  &lt;dependency&gt;
   &lt;groupId&gt;de.phpunit&lt;/groupId&gt;
   &lt;artifactId&gt;PHPUnit&lt;/artifactId&gt;
   &lt;version&gt;3.6.10&lt;/version&gt;
   &lt;type&gt;phar&lt;/type&gt;
  &lt;/dependency&gt;
 &lt;/dependencies&gt;
&lt;/project&gt;</pre>
<p>The test phase comes after creating your application, and for that you need the PHPUnit dependency. If it&#8217;s missing, be sure to add it to your <code>pom.xml</code> as shown above.</p>
<p>The PHPUnit tests should be place into the <code>src/test/php</code> folder and a test should be named <code><em>Somthing</em>Test.php</code>, that is, the suffix &#8220;Test.php&#8221; is a must. My test, <code>MyTest.php</code>, is listed below: </p>
<pre class="brush: php; title: ; notranslate">&lt;?php
class MyTest extends PHPUnit_Framework_TestCase
{
    public function testBar() {
        include &quot;org/sample/app.php&quot;;
        $this-&gt;fail(&quot;we will fail&quot;);
    }	
}</pre>
<p>To execute a test you use the command <code>mvn test</code>. In the official documentation has a section <a href="http://www.php-maven.org/branches/2.0-SNAPSHOT/tut-lifecycle-testing.html" title="Maven for PHP - testing phase" target="_blank">How to Ignore Failing Tests</a>, and you can find there some commands that may help you run your test. (The only command that actually worked for me was the one that executed a single test.)</p>
<p><img src="http://cdn.phpmaster.com/files/2013/05/maven-5.png" alt="maven-5" width="600" height="250" class="aligncenter size-full wp-image-5655" style="float:none !important; margin-left:auto; margin-right:auto;"></p>
<p>To build your newly created Maven project, you run the command <code>mvn:package</code>. You will notice again that Maven automatically starts downloading any dependencies needed for your project.</p>
<p>After downloading all needed dependencies and performing the build actions, you should get the following success message:</p>
<p><img src="http://cdn.phpmaster.com/files/2013/05/maven-6.png" alt="maven-6" width="600" height="138" class="aligncenter size-full wp-image-5656" style="float:none !important; margin-left:auto; margin-right:auto;"></p>
<p>To create documentation from the project, you’ll need the <a href="http://pear.phpdoc.org/" title="phpDocumentor channel" target="_blank">phpDocumentor 2 PEAR package</a>. In the <code>src/site</code> folder, create the <code>site.xml</code> file with the following contents:</p>
<pre class="brush: xml; title: ; notranslate">&lt;?xml version=&quot;1.0&quot; encoding=&quot;ISO-8859-1&quot;?&gt;
&lt;project name=&quot;Maven&quot;&gt;
 &lt;version position=&quot;left&quot; /&gt;

 &lt;skin&gt;
  &lt;groupId&gt;org.apache.maven.skins&lt;/groupId&gt;
  &lt;artifactId&gt;maven-stylus-skin&lt;/artifactId&gt;
  &lt;version&gt;1.0&lt;/version&gt;
 &lt;/skin&gt;
 &lt;body&gt;
  &lt;links&gt;
   &lt;item name=&quot;PHP-Maven&quot; href=&quot;http://www.php-maven.org/&quot; /&gt;
  &lt;/links&gt;

  &lt;menu name=&quot;Main&quot;&gt;
   &lt;item name=&quot;Welcome&quot; href=&quot;index.html&quot; /&gt;
  &lt;/menu&gt;

  &lt;menu ref=&quot;reports&quot; /&gt;
 &lt;/body&gt;
&lt;/project&gt;</pre>
<p>Next run the <code>mvn site</code> command and you&#8217;ll find the results in the <code>target/site</code> folder.</p>
<h2>Eclipse Integration</h2>
<p>The php-maven plugin supports integration with the Eclipse IDE, but it doesn’t contain the php-maven plugin by default. You need to integrate it manually. To do that, follow these steps:</p>
<ol>
<li>From the Help menu, choose Install New Software option and then press the &#8220;Add…&#8221; button.</li>
<li>In the Add Repository window enter the name: &#8220;PHPMaven update site&#8221; and URL <em>http://www.php-maven.org/eclipse/update</em>.</li>
<li>The PHPMaven update site is listed and you can choose the PHP-Maven option.</li>
<li>Hit Next/Finish to install the plugins.</li>
</ol>
<p><img src="http://cdn.phpmaster.com/files/2013/05/maven-7.png" alt="maven-7" width="600" height="328" class="aligncenter size-full wp-image-5657" style="float:none !important; margin-left:auto; margin-right:auto;"></p>
<p><img src="http://cdn.phpmaster.com/files/2013/05/maven-8.png" alt="maven-8" width="600" height="541" class="aligncenter size-full wp-image-5658" style="float:none !important; margin-left:auto; margin-right:auto;"></p>
<p>After the installation you will find the PHP-Maven project option when you go to create a new project. Select it, and press Next in order to install the plugin.</p>
<p>To create a new project within Eclipse, select File &gt; New &gt; Other (or press the CTRL + N combination) and you should see something like in the image below:</p>
<p><img src="http://cdn.phpmaster.com/files/2013/05/maven-9.png" alt="maven-9" width="525" height="500" class="aligncenter size-full wp-image-5659" style="float:none !important; margin-left:auto; margin-right:auto;"></p>
<p>After pressing the Next button you will receive a list of different archetypes.</p>
<p><img src="http://cdn.phpmaster.com/files/2013/05/maven-10.png" alt="maven-10" width="600" height="356" class="aligncenter size-full wp-image-5660" style="float:none !important; margin-left:auto; margin-right:auto;"></p>
<p>Choose your artifact and you will be prompted for the project information, just like earlier on the command prompt.</p>
<p><img src="http://cdn.phpmaster.com/files/2013/05/maven-11.png" alt="maven-11" width="600" height="310" class="aligncenter size-full wp-image-5661" style="float:none !important; margin-left:auto; margin-right:auto;"></p>
<p>The new project will be added to the Project Explorer tab. The folder structure is mostly similar to the one for the project created from command line.</p>
<p>After you create the project, right click on it and you&#8217;ll see the PHP-Maven option at the bottom of the menu, and its children list the most important phases of a PHP-Maven project.</p>
<p><img src="http://cdn.phpmaster.com/files/2013/05/maven-12.png" alt="maven-12" width="600" height="569" class="aligncenter size-full wp-image-5662" style="float:none !important; margin-left:auto; margin-right:auto;"></p>
<h2>Summary</h2>
<p>In this article you&#8217;ve learned how to install and use the PHP-Maven plugin from the command line and in Eclipse. Maven for PHP is a capable build automation tool for the PHP platform. Using Maven, the user only needs to provide the configuration for the project, while the configurable plugins do the work of compiling the project, running unit tests, generating API documentation and so on.  Maven for PHP will quickly become a necessary tool in the PHP developer&#8217;s toolbox.</p>
<p><small>Image via <a title="Royalty Free Stock Photos at Fotolia.com" href="http://us.fotolia.com/?utm_source=sitepoint&amp;utm_medium=website_link&amp;utm=campaign=sitepoint" target="_blank">Fotolia</a></small></p>
<img src="http://feeds.feedburner.com/~r/PHPMaster_feed/~4/dWSSFkDC7vo" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://phpmaster.com/maven-and-php/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		<feedburner:origLink>http://phpmaster.com/maven-and-php/</feedburner:origLink></item>
		<item>
		<title>Goodbye CodeIgniter, Hello Laravel</title>
		<link>http://feedproxy.google.com/~r/PHPMaster_feed/~3/XJHmF3qn8B8/</link>
		<comments>http://phpmaster.com/goodbye-codeigniter-hello-laravel/#comments</comments>
		<pubDate>Mon, 06 May 2013 14:30:14 +0000</pubDate>
		<dc:creator>Daniel Gafitescu</dc:creator>
				<category><![CDATA[Advanced]]></category>
		<category><![CDATA[PHP Tutorials]]></category>
		<category><![CDATA[Frameworks]]></category>

		<guid isPermaLink="false">http://phpmaster.com/?p=5614</guid>
		<description><![CDATA[A lot of developers are fanboys of their PHP framework of choice. Just like in politics, everyone chooses a side. And most of the time you can stay with your choice, but it’s always good to explore new things. For one developer it meant goodbye CodeIgniter, hello Laravel.]]></description>
				<content:encoded><![CDATA[<p>A lot of PHP developers are fan boys of their PHP framework, and there are quite a few from which you can choose. Among the most popular ones are CodeIgniter, Zend Framework, CakePHP, Symfony, Yii, and the new kids on the block Silex, Slim, Lithium, and Laravel.</p>
<p>In the beginning of my career I stumble upon CodeIgniter and I love it for its simplicity, small footprint, and good documentation. It worked great for me when I developed a small to medium sized applications (usually Facebook apps), and the learning curve for new developers who worked with me was shallow enough that they could easily be integrated in the development process.</p>
<p>But last year, because of the Twitter buzz from some in the PHP community, blog posts, and the suggestions of some friends, I give Laravel 3 a try – and since that time I’ve never looked back. So, in this article I’d like to present a comparison of the two frameworks from my point of view.</p>
<h2>Requirements</h2>
<p>CodeIgniter 2.1.3 needs PHP 5.1.6, but versions before 2 still worked with PHP 4. This was a drag since everybody moved on to use PHP 5. Laravel 3 needs PHP 5.3 and also the Mcrypt extension. </p>
<p>CodeIgniter 1 didn’t need Mcrypt, since if you didn’t have the extension installed then it would use a custom functions to encode/decode strings. Of course this slows down the application, and we were amazed at some of the production servers that didn’t have it installed.</p>
<pre class="brush: php; title: ; notranslate">&lt;?php
function encode($string, $key = '') {
    $key = $this-&gt;get_key($key);
    if ($this-&gt;_mcrypt_exists === true) {
        $enc = $this-&gt;mcrypt_encode($string, $key);
    }
    else {
        $enc = $this&gt;_xor_encode($string, $key);
    }
    return base64_encode($enc);
}</pre>
<h2>REST</h2>
<p>It’s easy to build a REST API with Laravel using <a href="http://laravel.com/docs/controllers#restfulcontrollers" title="Controllers - Laravel Documentation" target="_blank">RESTful Controllers</a> where you simply have the <code>$restful</code> property set true inside your controller. For example, if you’re building an API for a task manager, for updating a task it would use something like this:</p>
<pre class="brush: php; title: ; notranslate">&lt;?php
class Tasks_Controller extends Base_Controller {
    public $restful = true;
    public function get_index()
    {
    }
    public function put_update()
    {
    }
...
}</pre>
<p>To handle PUT in CodeIgniter you would need this workaround:</p>
<pre class="brush: php; title: ; notranslate">&lt;?php
if ($_SERVER[&quot;REQUEST_METHOD&quot;] == &quot;PUT&quot;) {
    parse_str(file_get_contents(&quot;php://input&quot;), $post_vars);
    $arData = json_decode(array_pop(array_keys($post_vars)));
}</pre>
<p>As you can see, this is error prone and not very clean.</p>
<h2>Code Organization</h2>
<p>Most of the time, the project you are working on will have a frontend and backend. In order to better organize the code in CodeIgniter, the best approach is to use <a href="https://github.com/Crypt/Codeigniter-HMVC" title="Crypt/Codeigniter-HMVC - GitHub" target="_blank">HMVC</a>. In this way you would have separate directories for backend code and frontend code so that different developers can work independently. To achieve something similar with Laravel, you can use <a href="http://laravel.com/docs/controllers#nested-controllers" title="Controllers - Laravel Documentation" target="_blank">nested controllers</a>.</p>
<h3>The View</h3>
<p>CodeIgniter doesn’t have a default template engine, but you can easily integrate one like <a href="https://github.com/cryode/CodeIgniter_Smarty" title="cryode/CodeIgniter_Smarty - GitHub" target="_blank">Smarty</a>. On the other hand, Laravel <a href="http://laravel.com/docs/views/templating#blade-template-engine" title="Templating - Laravel Documentation" target="_blank">uses Blade</a> as its template engine which is very simple but powerful. With Blade, it’s very easy to set up a <a href="http://martinfowler.com/eaaCatalog/twoStepView.html" title="P of EAA: Two Step View" target="_blank">two-step view</a>. </p>
<p>You have a master template where usually you put the basic HTML structure with a header, navigation, footer, etc. Most of the time this template is called <code>layout.blade.php</code> or <code>master.blade.php</code>. The portion of code that will be injected from different different controllers is declared in the master template by <code>@yield('content')</code>.</p>
<pre class="brush: xml; title: ; notranslate">&lt;!DOCTYPE HTML&gt;
&lt;html&gt;
 &lt;head&gt;
  ...
 &lt;/head&gt;
 &lt;body&gt;
  &lt;div class=&quot;header&quot;&gt;
   ...
  &lt;/div&gt;
  @yield('content')
 &lt;/body&gt;
&lt;/html&gt;</pre>
<p>In custom templates declared per each method of a controller, for example a CMS page like “About Us”, you have a template called <code>page.blade.php</code> which looks something like this:</p>
<pre class="brush: xml; title: ; notranslate">@layout('master')
...
@section('content')
About page section
@endsection
...</pre>
<p>You can have as many section as you like to declare and reuse.</p>
<p>A more detailed explanation about this can be found in the section <a href="http://codehappy.daylerees.com/blade-templates" title="Code Happy: Blade Templates" target="_blank">Blade Layouts</a> in the online open source book called <a href="http://codehappy.daylerees.com/" title="Code Happy: Code Happy" target="_blank">Code Happy</a> by Dayle Rees.</p>
<p>To achieve this in CodeIgniter, at least as far as I’ve been able to figure out, is to create a master controller which all other controllers extend and call a render method. A <a href="https://github.com/gafitescu/codeigniter-2-two-step-view" title="gafitescu/codeigniter-2-two-step-view - GitHub" target="_blank">CodeIgniter start project</a> for implementing two step views can be found under my GitHub account. </p>
<h3>The Model</h3>
<p>Codeigniter uses Active Record for database manipulation which is quite easy to master, but you can also use raw queries if you have complicated requirements. Laravel uses <a href="http://laravel.com/docs/database/eloquent" title="Eloquent - Laravel Documentation" target="_blank">Eloquent</a> as a ORM which is simple and works with major database servers. For writing queries, you can also use <a href="http://laravel.com/docs/database/fluent" title="Fluent Query Builder - Laravel Documentation" target="_blank">Fluent Query Builder</a>, which looks like a lot like the Active Record approach. And of course, you can also write raw queries too.</p>
<h2>Command Line (Crons)</h2>
<p>For Codeigniter to call a cron script, the best approach is to create a <code>Cron</code> controller. You also need to duplicate <code>index.php</code> and create a <code>cron.php</code> file right in the root directory, overriding the following the following <code>$_SERVER</code> values:</p>
<pre class="brush: php; title: ; notranslate">&lt;?php
$_SERVER['SERVER_NAME'] = &quot;xxxxxx.org&quot;;
$_SERVER['REQUEST_URI'] = &quot;cron/index&quot;;
$_SERVER['QUERY_STRING'] = &quot;lang=en&quot;;
$_SERVER['SERVER_PORT'] = &quot;0&quot;;
$_SERVER['REQUEST_METHOD'] = &quot;GET&quot;</pre>
<p>Then you can call it from the command line with <code>php cron.php cron index</code>.</p>
<p>In Laravel it’s easier. You have <a href="http://laravel.com/docs/artisan/tasks" title="Tasks - Laravel Documentation" target="_blank">Tasks</a> using the command line tool that Laravel comes with called Artisan.</p>
<h2>Miscellaneous</h2>
<ul>
<li><strong>Unit Testing</strong> – Codeigniter uses a very <a href="http://ellislab.com/codeigniter/user-guide/libraries/unit_testing.html" title="Unit Testing Class: CodeIgniter User Guide" target="_blank">rudimentary testing class</a> for writing unit tests. It is limited, but you can integrate PHPUnit. Laravel comes with PHPUnit out of the box, the most popular PHP unit testing framework.</li>
<li><strong>Authentication</strong> – Codeigniter doesn’t have anything out of the box for authentication, but you can always use a third-party library, like <a href="http://benedmunds.com/ion_auth/" title="Ion Auth Docs" target="_blank">Ion Auth</a>. Larvel on the other hand has a basic <a href="http://laravel.com/docs/auth/usage" title="Authentication Usage - Laravel Documentation" target="_blank">auth library</a> that you only need to configure before using.</li>
<li><strong>Caching</strong> – With CodeIgniter, the driver supports APC, Memcache, and the filesystem. Laravel on the other hand supports those and also database tables and Redis. </li>
<li><strong>Hooks/Filters</strong> – If you want to step in and run certain code at different points of execution in CodeIgniter, you should do so using <a href="http://ellislab.com/codeigniter/user-guide/general/hooks.html" title="Hooks: CodeIgniter User Guide" target="_blank">Hooks</a>.  Laravel offers <a href="http://laravel.com/docs/routing#filters" title="Routing - Laravel Documentation" target="_blank">Filters</a>.</li>
<li><strong>Routing</strong> – Routing is done pretty much the same way in both Laravel and CodeIgniter, although I’ve found Laravel to be more flexible.</li>
<li><strong>Configuration</strong> – Configuration is done via predefined arrays stored in config files which support multiple environments in both frameworks.</li>
<li><strong>Extensibility</strong> – Extending the core functionality of CodeIgniter is done with Libraries, and you can find a lot of them on <a href="http://getsparks.org/" title="CodeIgniter Sparks | The Package Manager and Repository" target="_blank">Sparks</a> (a package management system for CodeIgniter). Laravel uses <a href="http://laravel.com/docs/bundles" title="Bundles - Laravel Documentation" target="_blank">Bundles</a>, which might seem familiar to you if you’ve worked with Symfony 2. You can find check already-created bundles at <a href="http://bundles.laravel.com/" title="Laravel Bundles" target="_blank">bundles.laravel.com</a>.</li>
<li><strong>Migrations</strong> – <a href="http://laravel.com/docs/database/migrations" title="Migrations - Laravel Documentation" target="_blank">Database migrations</a> are specific for Laravel, a concept borrow from Ruby on Rails which is versioning at the database level.</li>
</ul>
<h2>Community</h2>
<p>CodeIgniter used to have a bigger community, but many moved to different frameworks after EllisLab, the company behind it, dropped support and no new features were added. Some of those people joined the Laravel community which is now very active with a lot of tutorials, books, and even its first international conference. </p>
<p>The future seems to be very bright for Laravel since Laravel 4 is in beta 2 and its first conference has just ended. On the other side for CodeIgniter, there are few member contributors who so commit/merge patches into CodeIgniter 2 but there is no release date for CodeIgniter 3.</p>
<h2>Conclusion</h2>
<p>With Laravel 4 on the horizon, the framework definitely has the momentum now and the community behind it is very active. I’m kind of nostalgic when I talk about CodeIgniter, but it served me very well at the time. It taught me how to use MVC, was easy to learn, earned me my first money, and I even did my first book review about it, but as time went on it hardly changed. Maybe it’s just because it was very good at what it did? But web development changes rapidly, and new technologies come around, so if you want to survive you have to keep up.</p>
<p>Just like in politics, everyone chooses a side. And for most of the time you can stick with your choice, but it’s always good to explore new things. For me, it meant goodbye CodeIgniter, hello Laravel.</p>
<p><small>Image via <a title="Royalty Free Stock Photos at Fotolia.com" href="http://us.fotolia.com/?utm_source=sitepoint&amp;utm_medium=website_link&amp;utm=campaign=sitepoint" target="_blank">Fotolia</a></small></p>
<img src="http://feeds.feedburner.com/~r/PHPMaster_feed/~4/XJHmF3qn8B8" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://phpmaster.com/goodbye-codeigniter-hello-laravel/feed/</wfw:commentRss>
		<slash:comments>30</slash:comments>
		<feedburner:origLink>http://phpmaster.com/goodbye-codeigniter-hello-laravel/</feedburner:origLink></item>
		<item>
		<title>MongoDB Indexing, Part 1</title>
		<link>http://feedproxy.google.com/~r/PHPMaster_feed/~3/mqTl0VyWhlo/</link>
		<comments>http://phpmaster.com/mongodb-indexing-1/#comments</comments>
		<pubDate>Fri, 03 May 2013 14:30:14 +0000</pubDate>
		<dc:creator>Ashish Trivedi</dc:creator>
				<category><![CDATA[Advanced]]></category>
		<category><![CDATA[PHP Tutorials]]></category>
		<category><![CDATA[Database]]></category>

		<guid isPermaLink="false">http://phpmaster.com/?p=5620</guid>
		<description><![CDATA[A proper understanding of indexing is critical because it can dramatically increase performance and throughput by reducing the number of full documents to be read, thereby increasing the performance of your application. This two-part series takes a look at indexing with MongoDB, starting here exploring the default _id index, secondary, compound, multikey, and multikey compound indexes.]]></description>
				<content:encoded><![CDATA[<p>Indexing is one of the more important concepts of working with MongoDB. A proper understanding is critical because indexing can dramatically increase performance and throughput by reducing the number of full documents to be read, thereby increasing the performance of our application. Because indexes can be bit difficult to understand, this two-part series will take a closer look at them.</p>
<p>In this article we’ll explore the following five types of indexes:</p>
<ol>
<li>Default _id Index</li>
<li>Secondary Index</li>
<li>Compound Index</li>
<li>Multikey Index</li>
<li>Multikey Compound Index</li>
</ol>
<p>There are some other types too to discuss, but I’ve logically kept them for part 2 to provide a clear understanding and avoid any confusion.</p>
<p>Although more than one index can be defined on a collection, a query can only use one index during its execution. The decision of choosing the best index out of the available options is made at runtime by MongoDB’s query-optimizer.</p>
<p>This article assumes that you have a basic understanding of MongoDB concepts (like Collections, Documents, etc.) and performing basic queries using PHP (like find and insert). If not, I suggest you to read our beginner articles: <a href="http://phpmaster.com/introduction-to-mongodb/" title="Introduction to MongoDB">Introduction to MongoDB</a> and <a href="http://phpmaster.com/mongodb-revisited/" title="MongoDB Revisited">MongoDB Revisited</a>.</p>
<p>For the series we’ll assume we have a collection named <code>posts</code> populated with 500 documents having the following structure:</p>
<pre class="brush: jscript; title: ; notranslate">{
    &quot;_id&quot;: ObjectId(&quot;5146bb52d852470060001f4&quot;),
    &quot;comments&quot;: {
        &quot;0&quot;: &quot;This is the first comment&quot;,
        &quot;1&quot;: &quot;This is the second comment&quot;
    },
    &quot;post_likes&quot;: 40,
    &quot;post_tags&quot;: {
        &quot;0&quot;: &quot;MongoDB&quot;,
        &quot;1&quot;: &quot;Tutorial&quot;,
        &quot;2&quot;: &quot;Indexing&quot;
    },
    &quot;post_text&quot;: &quot;Hello Readers!! This is my post text&quot;,
    &quot;post_type&quot;: &quot;private&quot;,
    &quot;user_name&quot;: &quot;Mark Anthony&quot;
}</pre>
<p>Now, let’s explore various types of indexing in detail.</p>
<h2>Default _id Index</h2>
<p>By default, MongoDB creates a default index on the <code>_id</code> field for each collection. Each document has a unique <code>_id</code> field as a primary key, a 12-byte ObjectID. When there are no other any indexes available, this is used by default for all kinds of queries.</p>
<p>To view the indexes for a collection, open the MongoDB shell and do the following:</p>
<p><img src="http://cdn.phpmaster.com/files/2013/05/mongo-1-1.png" alt="MongoDB Indexing, Part 1" width="714" height="293" class="aligncenter size-full wp-image-5632" style="margin-left:auto; margin-right: auto; float:none !important;"></p>
<p>The <code>getIndexes()</code> method returns all of the indexes for our collection. As you can see, we have the default index with name <em>_id_</em>. The <code>key</code> field indicates that the index is on the <code>_id</code> field, and the value of 1 indicates an ascending order. We&#8217;ll learn about ordering in next section.</p>
<h2>Secondary Index</h2>
<p>For cases where we want to use indexing on fields other than <code>_id</code> field, we have to define custom indexes. Suppose we want to search for posts based on the <code>user_name</code> field. In this case, we&#8217;ll define a custom index on the <code>user_name</code> field of the collection. Such custom indexes, other than the default index, are called secondary indexes.</p>
<p>To demonstrate the effect of indexing on database, let’s briefly analyze query performance without indexing first. For this, we’ll execute a query to find all posts having a <code>user_name</code> with “Jim Alexandar”.</p>
<pre class="brush: php; title: ; notranslate">&lt;?php
// query to find posts with user_name &quot;Jim Alexandar&quot;
$cursor = $collection-&gt;find(
    array(&quot;user_name&quot; =&gt; &quot;Jim Alexandar&quot;)
);
//  use explain() to get explanation of query indexes
var_dump($cursor-&gt;explain());</pre>
<p>An important method often used with indexing is <code>explain()</code> which returns information relevant to indexing. The output of the above <code>explain()</code> is as shown below:</p>
<p><img src="http://cdn.phpmaster.com/files/2013/05/mongo-1-2.png" alt="MongoDB Indexing, Part 1" width="510" height="410" class="aligncenter size-full wp-image-5633" style="margin-left:auto; margin-right: auto; float:none !important;"></p>
<p>Some of the important keys worth looking at are:</p>
<ol>
<li><strong><code>cursor</code></strong> – indicates the index used in the query. <em>BasicCursor</em> indicates that the default _id index was used and MongoDB had to search the entire collection. Going ahead, we’ll see that when we apply indexing, <em>BtreeCursor</em> will be used instead of <em>BasicCursor</em>.</li>
<li><strong><code>n</code></strong> – indicates the number of documents the query returned (one document in this case).</li>
<li><strong><code>nscannedObjects</code></strong> – indicates the number of documents searched by the query (in this case, all 500 documents of the collection were searched). This can be an operation with large overhead if the number of documents in collection is very large.</li>
<li><strong><code>nscanned</code></strong> – indicates the number of documents scanned during the database operation.</li>
</ol>
<p>Ideally, <code>n</code> should be equal to or near to <code>nscanned</code>, which means a minimum number of documents were searched.</p>
<p>Now, let’s execute the same query but using a secondary index. To create the index, execute the following in the MongoDB shell:</p>
<p><img src="http://cdn.phpmaster.com/files/2013/05/mongo-1-3.png" alt="MongoDB Indexing, Part 1" width="714" height="59" class="aligncenter size-full wp-image-5634" style="margin-left:auto; margin-right: auto; float:none !important;"></p>
<p>We created an index on the <code>user_name field</code> in the <code>posts</code> collection using the <code>ensureIndex()</code> method. I&#8217;m sure you&#8217;ve niced the value of the order argument to the method which indicates either an ascending (1) or descending (-1) order for the search. To better understand this, note that each document has a timestamp field. If we want the most recent posts first, we would use descending order. For the oldest posts first, we would choose ascending order.</p>
<p>After creating the index, the same <code>find()</code> and <code>explain()</code> methods are used to execute and analyze the query as before. The output of is:</p>
<p><img src="http://cdn.phpmaster.com/files/2013/05/mongo-1-4.png" alt="MongoDB Indexing, Part 1" width="510" height="117" class="aligncenter size-full wp-image-5635" style="margin-left:auto; margin-right: auto; float:none !important;"></p>
<p>The output shows that the query used a <em>BtreeCursor</em> named <em>user_name_1</em> (which we defined earlier) and scanned only one document as opposed to the 500 documents searched in the previous query without indexing.</p>
<p>For now, understand that all MongoDB indexes uses a BTree data structure in its algorithm, and BtreeCursor is the default cursor for it. A detailed discussion of BTreeCursor is out of scope for this article, but this doesn’t affect any further understanding.</p>
<p>The above comparison indicates how indexes can dramatically improve the the query performance. </p>
<h2>Compound Index</h2>
<p>There will be cases when a query uses more than one field. In such cases, we can use compound indexes. Consider the following query which uses both the <code>post_type</code> and <code>post_likes</code> fields:</p>
<pre class="brush: php; title: ; notranslate">&lt;?php
// query to find posts with type public and 100 likes
$cursor = $collection-&gt;find(
    array(
        &quot;post_type&quot; =&gt; &quot;public&quot;,
        &quot;post_likes&quot; =&gt; 100
    ),
    array()
);</pre>
<p>Analyzing this query with <code>explain()</code>, gives the following result, which shows that the query uses <code>BasicCursor</code> and all 500 documents are scanned to retrieve one document.</p>
<p><img src="http://cdn.phpmaster.com/files/2013/05/mongo-1-5.png" alt="MongoDB Indexing, Part 1" width="510" height="100" class="aligncenter size-full wp-image-5636" style="margin-left:auto; margin-right: auto; float:none !important;"></p>
<p>This is highly inefficient, so let&#8217;s apply some indexes. We can define a compound index on fields <code>post_type</code> and <code>post_likes</code> as follows:</p>
<p><img src="http://cdn.phpmaster.com/files/2013/05/mongo-1-6.png" alt="MongoDB Indexing, Part 1" width="714" height="59" class="aligncenter size-full wp-image-5637" style="margin-left:auto; margin-right: auto; float:none !important;"></p>
<p>Analyzing the query now gives the follow result:</p>
<p><img src="http://cdn.phpmaster.com/files/2013/05/mongo-1-7.png" alt="MongoDB Indexing, Part 1" width="510" height="100" class="aligncenter size-full wp-image-5638" style="margin-left:auto; margin-right: auto; float:none !important;"></p>
<p>A very important point of note here is that compound indexes defined on multiple fields can be used to query a subset of these fields. For example, suppose there is a compound index <code>{field1,field2,field3}</code>. This index can be used to query on:</p>
<ul>
<li><code>field1</code></li>
<li><code>field1, field2</code></li>
<li><code>field1, field2, field3</code></li>
</ul>
<p>So, if we&#8217;ve defined the index <code>{field1,field2,field3}</code>, we don’t need to define separate <code>{field1}</code> and <code>{field1,field2}</code> indexes. However, if we need this compound index while querying <code>field2</code> and <code>field2,field3</code>, we can use <code>hint()</code> if the optimizer doesn’t select the desired index.</p>
<p>The <code>hint()</code> method can be used to force MongoDB to use an index we specify and override the default selection and query optimization process. You can specify the field names used in the index as a argument as shown below:</p>
<pre class="brush: php; title: ; notranslate">&lt;?php
// query to find posts with type public and 100 likes
// use hint() to force MongoDB to use the index we created
$cursor = $collection
    -&gt;find(
        array(
            &quot;post_type&quot; =&gt; &quot;public&quot;,
            &quot;post_likes&quot; =&gt; 100
        )
    )
    -&gt;hint(
        array(
            &quot;post_type&quot; =&gt; 1,
            &quot;post_likes&quot; =&gt; 1
        )
    );</pre>
<p>This ensures the query uses the compound index defined on the <code>post_type</code> and <code>post_likes</code> fields. </p>
<h2>Multikey Index</h2>
<p>When indexing is done on an array field, it is called a multikey index. Consider our <code>post</code> document again; we can apply a multikey index on <code>post_tags</code>. The multikey index would index each element of the array, so in this case separate indexes would be created for the <code>post_tags</code> values: <em>MongoDB</em>, <em>Tutorial</em>, <em>Indexing</em>, and so on.</p>
<p><img src="http://cdn.phpmaster.com/files/2013/05/mongo-1-8.png" alt="MongoDB Indexing, Part 1" width="714" height="59" class="aligncenter size-full wp-image-5639" style="margin-left:auto; margin-right: auto; float:none !important;"></p>
<p>Indexes on array fields must be used very selectively, though, as they consume a lot of memory because of the indexing of each value.</p>
<h2>Multikey Compound Index</h2>
<p>We can create a multikey compound index, but with the limitation that at most one field in the index can be an array. So, if we have <code>field1</code> as a string, and <code>[field2, field3]</code> as an array, we can’t define the index <code>{field2,field3}</code> since both fields are arrays.</p>
<p>In the example below, we create an index on the <code>post_tags</code> and <code>user_name</code> fields:</p>
<p><img src="http://cdn.phpmaster.com/files/2013/05/mongo-1-9.png" alt="MongoDB Indexing, Part 1" width="714" height="59" class="aligncenter size-full wp-image-5640" style="margin-left:auto; margin-right: auto; float:none !important;"></p>
<h2>Indexing Limitations and Considerations</h2>
<p>It is important to know that indexing can’t be used in queries which use regular expressions, negation operators (i.e. <code>$ne</code>, <code>$not</code>, etc.), arithmetic operators (i.e. <code>$mod</code>, etc.), JavaScript expressions in the <code>$where</code> clause, and in some other cases.</p>
<p>Indexing operations also come with their own cost. Each index occupies space as well as causes extra overhead on each insert, update, and delete operation on the collection. You need to consider the read:write ratio for each collection; indexing is beneficial to read-heavy collections, but may not be for write-heavy collections.</p>
<p>MongoDB keeps indexes in RAM. Make sure that the total index size does not exceed the RAM limit. If it does, some indexes will be removed from RAM and hence queries will slow down. Also, a collection can have a maximum of 64 indexes.</p>
<h2>Summary</h2>
<p>That’s all for this part. To summarize, indexes are highly beneficial for an application if a proper indexing approach is chosen. <a href="http://phpmaster.com/mongodb-indexing-2/" title="MongoDB Indexing, Part 2">In the next part</a>, we’ll look at using indexes on embedded documents, sub-documents, and ordering. Stay tuned!</p>
<p><small>Image via <a title="Royalty Free Stock Photos at Fotolia.com" href="http://us.fotolia.com/?utm_source=sitepoint&amp;utm_medium=website_link&amp;utm=campaign=sitepoint" target="_blank">Fotolia</a></small></p>
<img src="http://feeds.feedburner.com/~r/PHPMaster_feed/~4/mqTl0VyWhlo" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://phpmaster.com/mongodb-indexing-1/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<series:name><![CDATA[MongoDB Indexing]]></series:name>
	<feedburner:origLink>http://phpmaster.com/mongodb-indexing-1/</feedburner:origLink></item>
		<item>
		<title>Crop and Resize Images with ImageMagick</title>
		<link>http://feedproxy.google.com/~r/PHPMaster_feed/~3/2UKuC3N_3Y4/</link>
		<comments>http://phpmaster.com/crop-and-resize-images-with-imagemagick/#comments</comments>
		<pubDate>Wed, 01 May 2013 14:30:28 +0000</pubDate>
		<dc:creator>Sandeep Panda</dc:creator>
				<category><![CDATA[Intermediate]]></category>
		<category><![CDATA[PHP Tutorials]]></category>

		<guid isPermaLink="false">http://phpmaster.com/?p=5574</guid>
		<description><![CDATA[If your site allows users to upload photos, then image cropping/resizing functionality can certainly come in handy. Users might not have access to image programs like Photoshop, so by providing a cropping/resizing feature you can let them upload photos without them having to worry about the final size. See how you can create an image cropping tool with the help of the ImageMagick PHP extension.]]></description>
				<content:encoded><![CDATA[<p>If your website allows users to upload photos, image cropping/resizing functionality certainly comes in handy. But users might not have access to image manipulation tools like Photoshop, so by providing a cropping/resizing feature you can allow users to upload photos from any device (e.g. tablets or phones) without them having to worry about the the final size. Furthermore, you can create different versions of the same image and also allow users to crop specific portions of uploaded picture.</p>
<p>In this article I&#8217;ll show you how to create an image cropping tool with the help of the ImageMagick PHP extension. This tutorial assumes that you already have the extension installed, so if not then be sure to <a href="http://php.net/manual/en/imagick.setup.php" title="PHP: Installing/Configuring - Manual" target="_blank">read the manual</a>.</p>
<h2>Getting Familiar</h2>
<p>The ImageMagick extension performs image processing using the ImageMagick library.  ImageMagick provides a lot of API methods through which you can manipulate an image. It offers a simple object-oriented interface to use the API; you just need to create an instance of the <code>Imagick</code> class and then call the appropriate methods to start manipulating the images.</p>
<p>Since we&#8217;re going to create an image cropper, we&#8217;ll mostly be using the two methods: <code>cropImage()</code> and <code>thumbnailimage()</code>.</p>
<h3>cropImage</h3>
<p>The <code>cropImage()</code> method accepts four arguments. The first two arguments indicate the height and width of the cropped region, and the last two indicate the X and Y coordinates of the top-left corner of the cropped area. </p>
<p>For example:</p>
<pre class="brush: php; title: ; notranslate">&lt;?php
$inFile = &quot;test.jpg&quot;;
$outFile = &quot;test-cropped.jpg&quot;;
$image = new Imagick($inFile);
$image-&gt;cropImage(400,400, 30,10);
$image-&gt;writeImage($outFile);</pre>
<p>We create an <code>Imagick</code> object first, passing to its constructor the filename of our image. Then we call <code>cropImage()</code> with appropriate arguments. In this case the code will produce a cropped image of size 400×400px starting at 30px from the top and 10px in from the left of the original image. Finally, <code>writeImage()</code> saves the result back to disk for us.</p>
<h3>thumbnailImage</h3>
<p>The <code>thumbnailImage()</code> method simply accepts the height and width of the resized image and can be used as follows:</p>
<pre class="brush: php; title: ; notranslate">&lt;?php
$inFile = &quot;test.jpg&quot;;
$outFile = &quot;test-thumbnail.jpg&quot;;
$image = new Imagick($inFile);
$image-&gt;thumbnailImage(200, 200);
$image-&gt;writeImage($outFile);</pre>
<p>The above code produces a 200×200px version of image. If either the width or height argument to <code>thumbnailImage()</code> is set as 0, the aspect ratio is maintained.</p>
<p>We can also pass a third argument known as <em>bestfit</em>; If this is set true, the image will be resized in such a way that the new dimensions can be contained within the height and width specified. For example, a call to <code>thumbnailImage(400, 400, true)</code> on a 1200×768px image will produce a 400×200px version. The new dimensions are less than or equal to the specified dimensions.</p>
<p>Now that you&#8217;re familiar with the two methods, we&#8217;re good to go.</p>
<h2>Upload and Cropping</h2>
<p>Of course we&#8217;ll need to create an HTML form with which users can upload photos:</p>
<pre class="brush: xml; title: ; notranslate">&lt;form action=&quot;upload.php&quot; method=&quot;post&quot; enctype=&quot;multipart/form-data&quot;&gt;
 &lt;label for=&quot;file&quot;&gt;Image:&lt;/label&gt;
 &lt;input type=&quot;file&quot; name=&quot;file&quot; id=&quot;file&quot;&gt;&lt;br&gt;
 &lt;input type=&quot;submit&quot; name=&quot;submit&quot; value=&quot;Upload and Crop&quot;&gt;
&lt;/form&gt;</pre>
<p>As soon as the user hits the upload button a POST request will be sent to a script which will handle the file upload process and show the uploaded image to the user for cropping. Remember, when uploading files you need to set the form&#8217;s <code>enctype</code> attribute to &#8220;multipart/form-data&#8221;.</p>
<p>An upload script handles the image upload and resizing the image if required.</p>
<pre class="brush: php; title: ; notranslate">&lt;?php
if (isset($_FILES[&quot;file&quot;])) {
    $tmpFile = $_FILES[&quot;file&quot;][&quot;tmp_name&quot;];
    $fileName = ... // determine secure name for uploaded file

    list($width, $height) = getimagesize($tmpFile);
    // check if the file is really an image
    if ($width == null &amp;&amp; $height == null) {
        header(&quot;Location: index.php&quot;);
        return;
    }
    // resize if necessary
    if ($width &gt;= 400 &amp;&amp; $height &gt;= 400) {
        $image = new Imagick($tmpFile);
        $image-&gt;thumbnailImage(400, 400);
        $image-&gt;writeImage($fileName);
    }
    else {
        move_uploaded_file($tmpFile, $fileName);
    }
}</pre>
<p>You should be very careful while accepting files from users as someone can upload a malicious file to your server if you don’t create a secure upload system. For more information, read the article <a href="http://phpmaster.com/file-uploads-with-php/" title="File Uploads with PHP">File Uploads with PHP</a>, paying special attention to the “Security Considerations” section.</p>
<p>The <code>getimagesize()</code> function returns a null height and width if the file is not an image, so if the code detects the file is not an image, it simply redirects the user elsewhere. Additionally, you can also check the image type and size of the file using <code>getimagesize()</code>, but in this case we just check if the file is an image based on the null values.</p>
<p>Since the script already knows the width and height of the uploaded image at this point, it can determine whether the image should be resized down. If dimensions are more than 400×400px, it&#8217;s resized to create a 400×400px thumbnail by calling <code>thumbnailImage()</code>. As I explained earlier, the method takes two parameters: width and height. If you want to maintain the image&#8217;s aspect ratio, it’s recommended to pass 0 as one of the arguments.</p>
<p>Finally, the resized image is saved by calling <code>writeImage()</code>, or moved with <code>move_uploaded_file()</code> if it was already a suitable size.</p>
<p>The saved image is outputted to the browser so that the user gets a chance to crop it. To allow users to select specific portion of the image, I use a jQuery plugin called <a href="http://odyniec.net/projects/imgareaselect/" title="imgAreaSelect - image selection/cropping jQuery plugin - odyniec.net" target="_blank">ImageAreaSelect</a>. To use the plugin, the jQuery library needs to be available, as well as the plugin&#8217;s CSS and JavaScript files. </p>
<pre class="brush: xml; title: ; notranslate">&lt;script type=&quot;text/javascript&quot; src=&quot;scripts/jquery.min.js&quot;&gt;&lt;/script&gt;
&lt;script type=&quot;text/javascript&quot; src=&quot;scripts/jquery.imgareaselect.pack.js&quot;&gt;&lt;/script&gt;
&lt;link rel=&quot;stylesheet&quot; type=&quot;text/css&quot; href=&quot;css/imgareaselect-default.css&quot;&gt;</pre>
<p>To initialize the plugin you can use the following code:</p>
<pre class="brush: jscript; title: ; notranslate">selection = $('#photo').imgAreaSelect({
    handles: true,
    instance: true
});</pre>
<p><code>#photo</code> is the id of the image shown to the user. By setting the <code>handles</code> property true you can show resize handles on the selection area, and <code>instance</code> true gets an instance and save it to the variable <code>selection</code>. It&#8217;s through <code>selection</code> that you can easily retrieve the selection area later when the user finalizes his cropping.</p>
<p><code>getSelection()</code> gives you everything you need. For example, <code>getSelection().width</code> gives you the width of the selection area. Similarly, you can use <code>getSelection().x1</code> and <code>getSelection().y1</code> to find the coordinates of the top left-corner of the selection area. </p>
<p>Putting this all together in a page, you&#8217;ll most likely register an <code>onclick</code> callback to a link or button, which the user can click to finalize his selection. When the button is clicked, the selection area width, height, and top-left corner coordinates is retrieved.</p>
<pre class="brush: jscript; title: ; notranslate">$(&quot;#crop&quot;).click(function(){
    var s = selection.getSelection();
    var width = s.width;
    var height = s.height;
    var x = s.x1;
    var y = s.y1;
    ...
});</pre>
<p>An Ajax request is sent to a cropping script, passing these values as request parameters since they are needed to crop the image through ImageMagick. Additionally, you&#8217;ll want to send the image name since the script will need to know the name of the image that it will be cropping.</p>
<pre class="brush: jscript; title: ; notranslate">var request = $.ajax({
    url: &quot;crop.php&quot;,
    type: &quot;GET&quot;,
    data: {
        x: x,
        y: y,
        height: height,
        width: width,
        image: $(&quot;#photo&quot;).attr(&quot;src&quot;)
    }
});</pre>
<p>When the request finishes, the image is reloaded so that the new cropped version will be shown in place of the old image.</p>
<pre class="brush: jscript; title: ; notranslate">request.done(function(msg) {
    $(&quot;#photo&quot;).attr(&quot;src&quot;, msg);
    selection.cancelSelection();
});</pre>
<p>When cropping is done, the request returns the name of the cropped image, and the new image is loaded by changing the <code>src</code> attribute.</p>
<p>So what does the cropping script look like?</p>
<pre class="brush: php; title: ; notranslate">&lt;?php
$file = basename($_GET[&quot;image&quot;]);
$cropped = &quot;cropped_&quot; . $file;
$image = new Imagick($file);
$image-&gt;cropImage($_GET[&quot;width&quot;], $_GET[&quot;height&quot;], $_GET[&quot;x&quot;], $_GET[&quot;y&quot;]);
$image-&gt;writeImage($cropped);
echo $cropped;</pre>
<p>The script first extracts the name of the image that needs to be cropped; the image name will be a full URL in the form of <em>http://example.com/path/image.jpg</em>, but only the <em>image.jpg</em> part is needed. Next, the string “cropped” is prefixed to the original name so that it will look like <em>cropped_image.jpg</em>. This allows the cropped image to be saved without overwriting the original. </p>
<p>The <code>cropImage()</code> method is used to crop the original image using the four parameters related to the selection area that were sent to the script, and then the cropped image is saved to the new file. The name of the cropped image is then echoed back to the Ajax request for display in the browser.</p>
<h2>Conclusion</h2>
<p>In this article I created a simple cropping tool to show you the power and easy of use of the ImageMagick extension. You can learn more about it, and be creative and make something more useful using its powerful API. For instance, if you wanted to extend what I&#8217;ve presented here, you could give users the option to download their images in multiple sizes. Sample code to accompany this article is available on the <a href="https://github.com/phpmasterdotcom/CropAndResizeWithImageMagick" title="phpmasterdotcom/CropAndResizeWithImageMagick - GitHub" target="_blank">PHPMaster GitHub page</a> to get you started.</p>
<p><small>Image via <a title="Royalty Free Stock Photos at Fotolia.com" href="http://us.fotolia.com/?utm_source=sitepoint&amp;utm_medium=website_link&amp;utm=campaign=sitepoint" target="_blank">Fotolia</a></small></p>
<img src="http://feeds.feedburner.com/~r/PHPMaster_feed/~4/2UKuC3N_3Y4" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://phpmaster.com/crop-and-resize-images-with-imagemagick/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		<feedburner:origLink>http://phpmaster.com/crop-and-resize-images-with-imagemagick/</feedburner:origLink></item>
	</channel>
</rss><!-- Performance optimized by W3 Total Cache. Learn more: http://www.w3-edge.com/wordpress-plugins/

Page Caching using memcached
Database Caching 14/66 queries in 0.192 seconds using memcached
Object Caching 864/1001 objects using memcached
Content Delivery Network via cdn.phpmaster.com

Served from: phpmaster.com @ 2013-05-24 07:49:37 -->
