Skip to content

Interesting jQuery toggling of a loading gif

2011 September 10
by Richard Knop

This is an interesting way to hide/show an AJAX loading gif image. Once an ajax request starts, the div containing the loading image shows up, once the request is done, the div is hidden again. I saw this on Stack Overflow and found it pretty:

  1. $('#ajax_loading_div')
  2. .hide()  // hide it initially
  3. .ajaxStart(function() {
  4.     $(this).show(); // show it when an AJAX request starts
  5. })
  6. .ajaxStop(function() {
  7.     $(this).hide(); // hide it when an AJAX request ends
  8. });

Merge PDF documents with Zend_Pdf

2011 June 28
by Richard Knop

Merging two or more PDF files with Zend_Pdf component of the Zend Framework is really simple. You just need to load the documents into Zend_Pdf instances and then iterate over their pages:

// load PDF documents
  1. $pdf1 = Zend_Pdf::load('first.pdf');
  2. $pdf2 = Zend_Pdf::load('second.pdf');
  3. // we will merge our two PDF files into a new Zend_Pdf object
  4. $pdfMerged = new Zend_Pdf();
  5.  
  6. // add all pages from the first PDF to our new document
  7. foreach($pdf1->pages as $page){
  8.     $clonedPage = clone $page;
  9.     $pdfMerged->pages[] = $clonedPage;
  10. }
  11. // add all pages from the second PDF to our new document
  12. foreach($pdf2->pages as $page){
  13.     $clonedPage = clone $page;
  14.     $pdfMerged->pages[] = $clonedPage;
  15. }
  16. unset($clonedPage);
  17.  
  18. // send the merged PDF document to browser
  19. header('Content-type: application/pdf');
  20. echo $pdfMerged->render();

A little bonus, if you need to load archived PDF documents (as I needed to recently) and merge them, you can use ZipArchive:

  1. $zip = new ZipArchive;
  2. $res = $zip->open('zipped_PDF_File.zip');
  3. $pdf = Zend_Pdf::parse($zip->getFromIndex(0));

Hope somebody finds it useful :)

PL/SQL cryptic warning: “Procedure created with compilation errors.”

2011 April 24
by Richard Knop

Many times PL/SQL won’t tell you what is wrong with your procedure and it will just print this cryptic message:

Warning: Procedure created with compilation errors.

If you don’t see any error in your code, use the following command:

SHOW ERRORS PROCEDURE <procedure_name>;

It will output something like which makes it much easier to debug the procedure:

SQL> SHOW ERRORS PROCEDURE add_book
Errors for PROCEDURE ADD_BOOK:

LINE/COL ERROR
-------- -----------------------------------------------------------------
28/3     PL/SQL: SQL Statement ignored
29/20    PL/SQL: ORA-00984: column not allowed here

You can use similar command not only with procedures:

SHOW ERRORS FUNCTION
SHOW ERRORS PACKAGE
SHOW ERRORS PACKAGE BODY
SHOW ERRORS TRIGGER
SHOW ERRORS VIEW
etc

Zend Framework rewrite rules for IIS7 web server

2011 February 13
by Richard Knop

UPDATE: I wrote a new more complete post explaining Zend Framework and IIS 7 configuration steb by step: Making Zend Framework run under IIS

If you are developing on a Windows PC you might want to use the native Windows web server IIS7 to run PHP. I do it that way. Since IIS neither accepts nor understands .htaccess files you will have to use a different approach to set up a Zend Framework project.

You will need to install the URL Rewrite module for IIS. Then just create a file called web.config in the public directory and put the following XML inside:

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <configuration>
  3.   <system.webServer>
  4.     <rewrite>
  5.       <rules>
  6.         <rule name="Imported Rule 1" stopProcessing="true">
  7.           <match url="^.*$" />
  8.           <conditions logicalGrouping="MatchAny">
  9.             <add input="{REQUEST_FILENAME}" matchType="IsFile" pattern="" ignoreCase="false" />
  10.             <add input="{REQUEST_FILENAME}" matchType="IsDirectory" pattern="" ignoreCase="false" />
  11.           </conditions>
  12.           <action type="None" />
  13.         </rule>
  14.         <rule name="Imported Rule 2" stopProcessing="true">
  15.           <match url="^.*$" />
  16.           <action type="Rewrite" url="index.php" />
  17.         </rule>
  18.       </rules>
  19.     </rewrite>
  20.   </system.webServer>
  21. </configuration>

Instead of manually creating the file you can also use the IIS Manager and import the rewrite rules through its interface.

Zend_Logger date() warning

2011 February 13
by Richard Knop

If you are getting a warning like this when you’re trying to write something to a log file with Zend_Logger:

Warning: date(): It is not safe to rely on the system's timezone settings. You are *required* to use the date.timezone setting or the date_default_timezone_set() function. In case you used any of those methods and you are still getting this warning, you most likely misspelled the timezone identifier. We selected 'Europe/Paris' for '1.0/no DST' instead in C:\inetpub\wwwroot\zend\library\Zend\Log.php on line 308

The solution is simple. I f you have access to your php.ini configuration file, just look for a line starting with:

date.timezone =

And put your timezone there, for example I used:

date.timezone = "Europe/Paris"

If you cannot edit the php.ini file, use this inside your PHP script:

  1. date_default_timezone_set("Europe/Paris");

Back online

2011 February 9
by Richard Knop

It’s good to be back online. This blog has been down for few weeks because I had some problems with my previous host. I lost some files so it took me a while to restore all data from the backup. Fortunatelly, I haven’t lost any written data (posts, pages etc). The only files missing were media files like images. I have uploaded back those pictures I had in the backup, I will try to replace the rest of them with new similar images soon.

I have already drawn new pictures for Adjacency list model and Nested set model posts. They don’t look quite as good as the previous ones. That’s because I have used GIMP to draw them this time and I have put only a little effort into it because I’m kinda busy right now :P

Zend_Navigation add class to active link

2010 September 6
by Richard Knop

It is often useful to highlight an active navigation menu link so users are clear about where they are. It is usually done by adding a class (for instance: “active”) to a link which points to a current request URI. When using Zend_Navigation it is a bit more complicated. I am using a controller plugin to add the class to the active link during the routeShutdown event:

  1. <?php
  2. class My_Controller_Plugin_PrepareNavigation extends Zend_Controller_Plugin_Abstract
  3. {
  4.     public function routeShutdown(Zend_Controller_Request_Abstract $request)
  5.     {
  6.         $viewRenderer = Zend_Controller_Action_HelperBroker::getExistingHelper('ViewRenderer');
  7.         $viewRenderer->initView();
  8.         $view = $viewRenderer->view;
  9.        
  10.         $container = new Zend_Navigation(Zend_Registry::get('configuration')->navigation);
  11.         foreach ($container->getPages() as $page) {
  12.             $uri = $page->getHref();
  13.             if ($uri === $request->getRequestUri()) {
  14.                 $page->setClass('active');
  15.             }
  16.         }
  17.         $view->navigation($container);
  18.     }
  19. }

Action helper that converts SQL result to XML

2010 September 6
by Richard Knop

Here is a simple Zend Framework controller action helper that converts SQL result to XML. The SQL result should be fetched as an object or an array of objects:

  1. <?php
  2. class My_Controller_Action_Helper_SqlToXml extends Zend_Controller_Action_Helper_Abstract
  3. {
  4.     public function direct($sqlResult, $rootElementName, $childElementName, $singleRow, $encoding = 'UTF-8')
  5.     {
  6.         // create XML documnt      
  7.         $doc = new DomDocument('1.0', $encoding);
  8.        
  9.         // insert a root element
  10.         $root = $doc->createElement($rootElementName);
  11.         $root = $doc->appendChild($root);
  12.        
  13.         // if the SQL result set contains only a singler row
  14.         if (true === $singleRow) {
  15.             $xmlData .= $this->rowToXml($doc, $root, $sqlResult, $childElementName);
  16.         }
  17.         // if the SQL result set is an object array
  18.         else if (false === $singleRow) {
  19.             foreach ($sqlResult as $row) {
  20.                 $xmlData .= $this->rowToXml($doc, $root, $row, $childElementName);
  21.             }
  22.         }
  23.        
  24.         // return XML string
  25.         return $doc->saveXML();
  26.     }
  27.    
  28.     private function rowToXml($doc, $root, $row, $childElementName)
  29.     {
  30.         // insert a child element
  31.         $occ = $doc->createElement($childElementName);
  32.           $occ = $root->appendChild($occ);        
  33.          
  34.           // iterate through each public object property and insert a shild element
  35.         foreach ($row as $property => $value) {
  36.             $child = $doc->createElement($property);
  37.             $child = $occ->appendChild($child);
  38.            
  39.             $childValue = $doc->createTextNode($value);
  40.             $childValue = $child->appendChild($childValue);
  41.         }
  42.     }
  43. }

Hope some of you will find it useful.

Solution to “imagettfbbox() [function.imagettfbbox]: Could not find/open font”

2010 August 21
by Richard Knop

If you are using the imagettfbbox() PHP function and come across this error:

imagettfbbox() [function.imagettfbbox]: Could not find/open font

The solution is to use neither relative nor absolute path to the font but to use a path like this:

$font = './arial.ttf';

Send email with attachment with PHP mail()

2010 July 16
by Richard Knop

I am posting this function mainly for my own reference. I am making sure I can just copy and paste this function in the future without having to go through that silly headers mambo jumbo again. This function will correctly map a file extension to a mime type and send both plain text and html versions of email. Here it is:

  1. function sendEmailWithAttachment($toName, // recipient's name
  2.      $toEmail, // recipient's email
  3.      $fromName, // sender's name
  4.      $fromEmail, // sender's email
  5.      $emailText, // plain text email body
  6.      $emailHtml, // html email body
  7.      $fileToAttach /* path to a file you want to attach */)
  8. {
  9.  
  10.  $emailText = wordwrap($emailText, 70);
  11.  
  12.  $headers  = "To: $toName <$toEmail>\r\n";
  13.  $headers .= "From: $fromName <$fromEmail>\r\n";
  14.  
  15.  $random_hash = md5(date('r', time()));
  16.  $headers .= 'Content-Type: multipart/mixed; boundary="PHP-mixed-' . $random_hash . '"';
  17.  
  18.  $mimeTypes = array(
  19.   "323" => "text/h323",
  20.   "acx" => "application/internet-property-stream",
  21.   "ai" => "application/postscript",
  22.   "aif" => "audio/x-aiff",
  23.   "aifc" => "audio/x-aiff",
  24.   "aiff" => "audio/x-aiff",
  25.   "asf" => "video/x-ms-asf",
  26.   "asr" => "video/x-ms-asf",
  27.   "asx" => "video/x-ms-asf",
  28.   "au" => "audio/basic",
  29.   "avi" => "video/x-msvideo",
  30.   "axs" => "application/olescript",
  31.   "bas" => "text/plain",
  32.   "bcpio" => "application/x-bcpio",
  33.   "bin" => "application/octet-stream",
  34.   "bmp" => "image/bmp",
  35.   "c" => "text/plain",
  36.   "cat" => "application/vnd.ms-pkiseccat",
  37.   "cdf" => "application/x-cdf",
  38.   "cer" => "application/x-x509-ca-cert",
  39.   "class" => "application/octet-stream",
  40.   "clp" => "application/x-msclip",
  41.   "cmx" => "image/x-cmx",
  42.   "cod" => "image/cis-cod",
  43.   "cpio" => "application/x-cpio",
  44.   "crd" => "application/x-mscardfile",
  45.   "crl" => "application/pkix-crl",
  46.   "crt" => "application/x-x509-ca-cert",
  47.   "csh" => "application/x-csh",
  48.   "css" => "text/css",
  49.   "dcr" => "application/x-director",
  50.   "der" => "application/x-x509-ca-cert",
  51.   "dir" => "application/x-director",
  52.   "dll" => "application/x-msdownload",
  53.   "dms" => "application/octet-stream",
  54.   "doc" => "application/msword",
  55.   "dot" => "application/msword",
  56.   "dvi" => "application/x-dvi",
  57.   "dxr" => "application/x-director",
  58.   "eps" => "application/postscript",
  59.   "etx" => "text/x-setext",
  60.   "evy" => "application/envoy",
  61.   "exe" => "application/octet-stream",
  62.   "fif" => "application/fractals",
  63.   "flr" => "x-world/x-vrml",
  64.   "gif" => "image/gif",
  65.   "gtar" => "application/x-gtar",
  66.   "gz" => "application/x-gzip",
  67.   "h" => "text/plain",
  68.   "hdf" => "application/x-hdf",
  69.   "hlp" => "application/winhlp",
  70.   "hqx" => "application/mac-binhex40",
  71.   "hta" => "application/hta",
  72.   "htc" => "text/x-component",
  73.   "htm" => "text/html",
  74.   "html" => "text/html",
  75.   "htt" => "text/webviewhtml",
  76.   "ico" => "image/x-icon",
  77.   "ief" => "image/ief",
  78.   "iii" => "application/x-iphone",
  79.   "ins" => "application/x-internet-signup",
  80.   "isp" => "application/x-internet-signup",
  81.   "jfif" => "image/pipeg",
  82.   "jpe" => "image/jpeg",
  83.   "jpeg" => "image/jpeg",
  84.   "jpg" => "image/jpeg",
  85.   "js" => "application/x-javascript",
  86.   "latex" => "application/x-latex",
  87.   "lha" => "application/octet-stream",
  88.   "lsf" => "video/x-la-asf",
  89.   "lsx" => "video/x-la-asf",
  90.   "lzh" => "application/octet-stream",
  91.   "m13" => "application/x-msmediaview",
  92.   "m14" => "application/x-msmediaview",
  93.   "m3u" => "audio/x-mpegurl",
  94.   "man" => "application/x-troff-man",
  95.   "mdb" => "application/x-msaccess",
  96.   "me" => "application/x-troff-me",
  97.   "mht" => "message/rfc822",
  98.   "mhtml" => "message/rfc822",
  99.   "mid" => "audio/mid",
  100.   "mny" => "application/x-msmoney",
  101.   "mov" => "video/quicktime",
  102.   "movie" => "video/x-sgi-movie",
  103.   "mp2" => "video/mpeg",
  104.   "mp3" => "audio/mpeg",
  105.   "mpa" => "video/mpeg",
  106.   "mpe" => "video/mpeg",
  107.   "mpeg" => "video/mpeg",
  108.   "mpg" => "video/mpeg",
  109.   "mpp" => "application/vnd.ms-project",
  110.   "mpv2" => "video/mpeg",
  111.   "ms" => "application/x-troff-ms",
  112.   "mvb" => "application/x-msmediaview",
  113.   "nws" => "message/rfc822",
  114.   "oda" => "application/oda",
  115.   "p10" => "application/pkcs10",
  116.   "p12" => "application/x-pkcs12",
  117.   "p7b" => "application/x-pkcs7-certificates",
  118.   "p7c" => "application/x-pkcs7-mime",
  119.   "p7m" => "application/x-pkcs7-mime",
  120.   "p7r" => "application/x-pkcs7-certreqresp",
  121.   "p7s" => "application/x-pkcs7-signature",
  122.   "pbm" => "image/x-portable-bitmap",
  123.   "pdf" => "application/pdf",
  124.   "pfx" => "application/x-pkcs12",
  125.   "pgm" => "image/x-portable-graymap",
  126.   "pko" => "application/ynd.ms-pkipko",
  127.   "pma" => "application/x-perfmon",
  128.   "pmc" => "application/x-perfmon",
  129.   "pml" => "application/x-perfmon",
  130.   "pmr" => "application/x-perfmon",
  131.   "pmw" => "application/x-perfmon",
  132.   "pnm" => "image/x-portable-anymap",
  133.   "pot" => "application/vnd.ms-powerpoint",
  134.   "ppm" => "image/x-portable-pixmap",
  135.   "pps" => "application/vnd.ms-powerpoint",
  136.   "ppt" => "application/vnd.ms-powerpoint",
  137.   "prf" => "application/pics-rules",
  138.   "ps" => "application/postscript",
  139.   "pub" => "application/x-mspublisher",
  140.   "qt" => "video/quicktime",
  141.   "ra" => "audio/x-pn-realaudio",
  142.   "ram" => "audio/x-pn-realaudio",
  143.   "ras" => "image/x-cmu-raster",
  144.   "rgb" => "image/x-rgb",
  145.   "rmi" => "audio/mid",
  146.   "roff" => "application/x-troff",
  147.   "rtf" => "application/rtf",
  148.   "rtx" => "text/richtext",
  149.   "scd" => "application/x-msschedule",
  150.   "sct" => "text/scriptlet",
  151.   "setpay" => "application/set-payment-initiation",
  152.   "setreg" => "application/set-registration-initiation",
  153.   "sh" => "application/x-sh",
  154.   "shar" => "application/x-shar",
  155.   "sit" => "application/x-stuffit",
  156.   "snd" => "audio/basic",
  157.   "spc" => "application/x-pkcs7-certificates",
  158.   "spl" => "application/futuresplash",
  159.   "src" => "application/x-wais-source",
  160.   "sst" => "application/vnd.ms-pkicertstore",
  161.   "stl" => "application/vnd.ms-pkistl",
  162.   "stm" => "text/html",
  163.   "svg" => "image/svg+xml",
  164.   "sv4cpio" => "application/x-sv4cpio",
  165.   "sv4crc" => "application/x-sv4crc",
  166.   "t" => "application/x-troff",
  167.   "tar" => "application/x-tar",
  168.   "tcl" => "application/x-tcl",
  169.   "tex" => "application/x-tex",
  170.   "texi" => "application/x-texinfo",
  171.   "texinfo" => "application/x-texinfo",
  172.   "tgz" => "application/x-compressed",
  173.   "tif" => "image/tiff",
  174.   "tiff" => "image/tiff",
  175.   "tr" => "application/x-troff",
  176.   "trm" => "application/x-msterminal",
  177.   "tsv" => "text/tab-separated-values",
  178.   "txt" => "text/plain",
  179.   "uls" => "text/iuls",
  180.   "ustar" => "application/x-ustar",
  181.   "vcf" => "text/x-vcard",
  182.   "vrml" => "x-world/x-vrml",
  183.   "wav" => "audio/x-wav",
  184.   "wcm" => "application/vnd.ms-works",
  185.   "wdb" => "application/vnd.ms-works",
  186.   "wks" => "application/vnd.ms-works",
  187.   "wmf" => "application/x-msmetafile",
  188.   "wps" => "application/vnd.ms-works",
  189.   "wri" => "application/x-mswrite",
  190.   "wrl" => "x-world/x-vrml",
  191.   "wrz" => "x-world/x-vrml",
  192.   "xaf" => "x-world/x-vrml",
  193.   "xbm" => "image/x-xbitmap",
  194.   "xla" => "application/vnd.ms-excel",
  195.   "xlc" => "application/vnd.ms-excel",
  196.   "xlm" => "application/vnd.ms-excel",
  197.   "xls" => "application/vnd.ms-excel",
  198.   "xlt" => "application/vnd.ms-excel",
  199.   "xlw" => "application/vnd.ms-excel",
  200.   "xof" => "x-world/x-vrml",
  201.   "xpm" => "image/x-xpixmap",
  202.   "xwd" => "image/x-xwindowdump",
  203.   "z" => "application/x-compress",
  204.   "zip" => "application/zip"
  205.  );
  206.  
  207.  $extension = end(explode('.', $fileToAttach));
  208.  $mimeType = $mimeTypes[$extension];
  209.  $fileName = end(explode('/', $fileToAttach));
  210.  
  211.  $attachment = chunk_split(base64_encode(file_get_contents($fileToAttach)));
  212.  
  213. $output = "
  214. –PHP-mixed-$random_hash;
  215. Content-Type: multipart/alternative; boundary='PHP-alt-$random_hash'
  216. –PHP-alt-$random_hash
  217. Content-Type: text/plain; charset='iso-8859-1'
  218. Content-Transfer-Encoding: 7bit
  219.  
  220. $emailText
  221.  
  222. –PHP-alt-$random_hash
  223. Content-Type: text/html; charset='iso-8859-1'
  224. Content-Transfer-Encoding: 7bit
  225.  
  226. $emailHtml
  227.  
  228. –PHP-alt-$random_hash–
  229.  
  230. –PHP-mixed-$random_hash
  231. Content-Type: application/$mimeType; name=$fileName
  232. Content-Transfer-Encoding: base64
  233. Content-Disposition: attachment
  234.  
  235. $attachment
  236. –PHP-mixed-$random_hash–";
  237.  
  238.  mail($toEmail, $subject, $output, $headers);
  239.  
  240. }

Hope somebody will find it useful.