CakePHP and dompdf autoload error

February 2nd, 2010

I recently tried using dompdf in a CakePHP project to easily generate PDFs from HTML. I ran into a rather obtuse error while trying to render a page and generate a PDF in the same controller action.

Fatal error: require_once() [function.require]: Failed opening required 'vendors/dompdf/include/htmlhelper.cls.php' in vendors/dompdf/dompdf_config.inc.php on line 194

That makes it seem a lot like dompdf is trying to include one of its files and failing. What’s really happening is dompdf is specifying an __autoload function which PHP is attempting to use to load the HtmlHelper class used by CakePHP. dompdf blindly includes the file if it exists or not thinking only its files would be loaded this way. To get around this and load the files normally, simply edit the DOMPDF_autoload function to make sure the file exists before including.

function DOMPDF_autoload($class) {
    $filename = DOMPDF_INC_DIR . "/" . mb_strtolower($class) . ".cls.php";
    if(is_file($filename)) {
        require_once($filename);
    }
}

I found this snippet after much searching over at http://www.dashinteractive.net/dompdf/index.php?v=3278826, hopefully this post will save someone else a few minutes of googling.

Loading app models inside a plugin controller in CakePHP

January 21st, 2010

I recently ran into a problem while writing a plugin in CakePHP. I wanted to do some authentication with one of the models in my app. I added this in the beforeFilter of my AppController. In there I was using $this->loadModel to load the model on the fly. This works fine inside the app. However, as soon as you move to a plugin things break down. It will try to load the model inside your plugin. Since that model doesn’t exist in the plugin, it will fail. You can specify a plugin in the loadModel call, like ‘Plugin.Model’, but you can’t specify no plugin. The way to get it to load correctly is the $uses variable. That will load the correct model when initializing the controller. Then you can use it as normal with $this->Model. This has the side effect of always loading the model on every controller. In my case that was perfectly fine since its used for auth on all actions. I can’t see any viable way to use loadModel to load a model outside of your plugin.

0 Size Mac Fonts

October 15th, 2009

This no longer works in Snow Leopard

I was trying to do this again after upgrading to Snow Leopard and the OS no longer handles extended attributes in the same fashion. Attributes are now in a new style and the old style attributes you can only print out the hex. To get the value you have to do xattr -px com.apple.ResourceFork file_name | xxd -r -p > file_name.ttf. I tried this a few times and even though the file contents matches up exactly with the resource fork, the font does not appear to work. I also noticed that simply copying or moving the individual fonts on my Mac would cause them to stop working.

I just ran into a very weird issue today trying to transfer fonts from a Mac to a PC. I had several fonts on my mac that were working, installable, usable, and showed as having a size. When I tried sending them to a friend they would show up as 0k. I tried sending individual fonts, as a zip, via gmail, from a link, nothing worked. I decided to take a look at the files, opening them in a text editor showed nothing. Listing their file size in the terminal showed them as 0 bytes. The only place I could think of that data being stored was somewhere in the file attributes.

Back in OS 9 Mac fonts used to store their data in the resource fork. Normally this is used for storing metadata about a file. Someone at Apple decided that putting fonts in there was a good idea. Now in OS X the resource fork has been moved to the extended attribute com.apple.ResourceFork. Extended attributes are not used in file size calculations by terminal. If you want to see the extended attributes you can use xattr -l file_name. Running that on the font file showed a giant chunk of data in com.apple.ResourceFork that was definitely the font info. Mystery solved.

Converting the file is easy once you figure this out. You can simply dump the resource fork into a file with the extension .ttf and OS X will interpret it as a PC true type font. Use xattr -p com.apple.ResourceFork file_name > file_name.ttf to get the data. This will allow you to copy the file to a PC. I make absolutely no promises as to how well this works, but it worked for me. You can also try converting using transtype http://www.fontlab.com/font-converter/transtype/

Redirecting to requested URL in CakePHP with custom auth controller

August 20th, 2009

I recently ran into the problem of having to redirect a user back to their requested url after logging in. In CakePHP you would normally use Auth::redirect() and that handles it for you. However, I had already written a custom authentication function in my app_controller. I simply wanted to figure out which url the user had requested, save that in the session, and send them back there after a successful login. This may seem like a very simple thing to do, but getting your current URL isn’t so easy in CakePHP.

The best solution I found was to use Router::getParams(). This will return you an array of info about the request. The currently request url, relative to you CakePHP install, will be in will be in ['url']['url']. The URL does not have a starting slash, unless the requested page was ‘/’. For example if you have CakePHP installed in http://www.mysite.com/cake_test/ and you request http:/www.mysite.com/cake_test/users/edit/15 the URL will be ‘users/edit/15′. So to add this into my auth controller I simply added:

$request_params = Router::getParams();
$this->Session->write('auth_redirect','/'.$request_params['url']['url']);

Then after a successful login you can simply:
$this->redirect($this->Session->read('auth_redirect'));

iPhone SQLite ‘no such table’ error

June 4th, 2009

I recently ran into an annoying problem getting data from an SQLite database in my iPhone application. I had bundled the database with the application and duplicated code from Apple’s example code. No matter what I did every time I tried to select from my table I would get “no such table: table_name”. I tried checking what tables existed in the database using “SELECT name FROM sqlite_master WHERE type = ‘table’”, and found there were none.

What happened is sqlite3_open() will create a new database if it can’t find the one you requested. It will also cache this empty database and use it in the simulator. So even though I had fixed the issue with my code, that empty database was still being used. The solution to this is to delete the app from the simulator (click and hold the app icon, then click the x) and re-build. This will clear the cached database and use the copy bundled with your app.

Hopefully this will help someone else avoid a few hours of annoyance. It seems to be a fairly common pitfall, but I wasn’t able to find much in the way of answers.

MS Access getting last insert id from @@IDENTITY with triggers

March 16th, 2009

I ran into a wonderful issue with the way MS Access handles getting the last insert id from SQL Server. The application would fail saying ‘record was deleted’ when trying to access the newly created object. I had determined that this was because of some logging triggers I had created. Removing the triggers solved the problem.

I could not see how my trigger would be affecting the insert statement, it fired after and operated on a separate table. After a bit of testing I determined that MS Access was using the @@IDENTITY variable to get the id of the newly created record. This is a poor choice. There is IDENT_CURRENT(`table_name`) as well as SCOPE_IDENTITY(), both of which would avoid the issue. @@IDENTITY is set on any insert statement for the connection, this includes any triggers. The logging trigger inserted a new record, overwriting @@IDENTITY. So then MS Access would get that id back, try to look up the record and fail. Or worse, look up the wrong record.

My lame solution to this lame problem was to set @@IDENTITY back to the original insert id. However, the only way to do this is by inserting a new record with the table’s identity column set to the original insert id.

To do this I created a new table.

CREATE TABLE insert_id_fix (id INT IDENTITY)

Then before I do my logging insert, save the value of @@IDENTITY to a local variable.

DECLARE @insert_id INT
SET @insert_id = @@IDENTITY

Then after inserting the log, insert a new record into the insert_id_fix table.

    SET IDENTITY_INSERT insert_id_fix ON
    INSERT INTO insert_id_fix (id) VALUES(@insert_id)
    SET IDENTITY_INSERT insert_id_fix OFF
    DELETE FROM insert_id_fix

Notice we have to SET IDENTITY_INSERT ON for the table to insert our value into the IDENTITY column. I also cleared the table since we don’t want to actually keep the data.

Another solution would be to change the trigger to be INSTEAD OF and process the insert yourself after doing the logging. This might be a better solution, but has its issues too.

As far as I know this is a problem with MS Access itself, not the application. I could be wrong as I didn’t write the application myself. The error occurred when accessing the newly created object, which should’ve been handled by Access. If anyone has further insight into how Access works, please comment.

Using Zend to parse raw SMTP email data

March 11th, 2009

I needed to create a script today that takes raw SMTP input from stdin. The project is running on Zend and they have a library for email. However, their documentation is geared toward getting that email from a mailserver. As far as I could find there wasn’t an example of how to create an email object out of the raw SMTP data.

Create a Zend_Mail_Message from the raw string.

$email = new Zend_Mail_Message(array('raw' => $email_str));

To grab the subject:

$email->subject;

All I wanted was the body from the text/plain piece of the email. If you’ve got a multi-part message it’s a little tricky. Here’s what I compiled from Zend’s documentation:

if($email->isMultipart()) {
  foreach (new RecursiveIteratorIterator($email) as $part) {
    try {
      if (strtok($part->contentType, ';') == 'text/plain') {
        $body = trim($part);
        break;
      }
    } catch (Zend_Mail_Exception $e) { // ignore }
  }
  if(!$body) {
    //Error
  }
} else {
  $body = trim($email->getContent());
}

MSSQL Bitwise Operations Using Two Varbinary Variables And COLUMNS_UPDATED()

January 19th, 2009

While trying to write some triggers for MSSQL I stumbled upon this nice function called COLUMNS_UPDATED(). It returns a bitmask representing the columns that were modified during an update operation. It just so happened that this was exactly what I was looking for. I had a group of columns that I wanted the trigger to act upon, the rest I didn’t care about. So I went about creating a bitmask for my columns to & against COLUMNS_UPDATED(). Here is where I ran into two problems.

First, COLUMNS_UPDATED() returns a VARBINARY, so logically I also made mine a VARBINARY. Unfortunately, MSSQL does not support bitwise operations on two VARBINARY variables. One can be a VARBINARY, but the other must be an INT. This isn’t a problem if your table is 32 columns or less. Unfortunately that was not the case for the 74-column monster of a table I was working with. I searched around and it seemed like there really wasn’t a solution to this problem. So I wrote my own. It’s a stored procedure that will perform the bitwise operations, &, |, or ^ on two VARBINARY variables. It splits the VARBINARY variables into INT sized chunks and the performs the operations. I’m sure it could be more efficient, but it works.
binary_bitwise.sql

The second wonderful thing is the way that bits are organized. Withing each byte (8 bits) the least significant bit (rightmost) is the first column. So if you were interested in columns 1,3,4 you would get: 00001101. Then within your whole bitmask the most significant byte (leftmost) is the first 8 columns. So let’s say you were interested in columns 1,3,4,7,9,15,16 then you would get 01001101 11000001. Writing out the bits in order doesn’t make much sense to the human brain, notice columns 15 and 16 are in the middle. The easiest way I found is to write out 0s in byte sized groups then go through them backwards putting 1s in your columns.
Once you figure out your bitmask convert it to a hex number and you can use in the trigger. My monster table ended up with:

IF(dbo.binary_bitwise(COLUMNS_UPDATED(),0xFFF57851150404C02102,'&') != 0x0)

. Also remember to fill out all your bits. If you only have 12 columns, you still need 16 bits. Let’s say you are interested in column 2 and 11. 00000010 00000100 = 0×24.

Troubleshooting with Zend XML RPC

September 15th, 2008

Zend has a wonderful XML RPC library built into their framework. You create a class with member functions that are accessible via RPC. It even uses heredoc syntax for the typing of parameters. All you have to do is register the class with the XML RPC server and it automagically works.

Unless it doesn’t. Which is where the hard part comes in. As a client there’s no way to see the raw HTTP response from the server. You can grab the Zend_Http_Client from the Zend_XmlRpc_Client. This will give you access to

Zend_Http_Client->raw_post_data

which is how Zend_XmlRpc_Client sends the request. The response however, is much harder to get. When Zend_XmlRpc_Client receives a response it uses a Zend_Http_Response, but it’s never stored. It passes the data over to a Zend_Xml_Response and returns that. Which is great if the page is valid XML. But if PHP throws an exception or you just want to look at the raw HTTP it’s gone. To get around this I added a variable to the Zend_XmlRpc_Client to store the Zend_Http_Response before it’s destroyed. Then added in a function to return it and voila. To check the raw response you just have to

Zend_XmlRpc_Client->getLastHttpResponse()->getBody()

Zend and Doctrine on Mac OS X Leopard

September 11th, 2008

I recently spent several hours beating my head against the wall trying to figure out why Doctrine and Zend weren’t playing nice together. I was using the version of Apache and PHP that comes with Mac OS X Leopard. When trying to load up the site in my Zend framework I got the error:

Warning: Zend_Loader::include_once(Doctrine/Adapter/Mysql.php): failed to open stream: No such file or directory

Which made me think I was missing the mysql adapter for Doctrine. Looking in the Doctrine/Adapter folder, at least with the latest version, you’ll notice there is only a Mysqli.php no Mysql.php. This led me to think that I was missing some essential library for Doctrine. However, this was not the case. The issue is that the build of PHP that comes with Mac OS X Leopard does not include pdo_mysql. The extension is listed in the php.ini file and you can uncomment it, but it won’t load. Rather than try and compile PHP with pdo_mysql support I decided to move to MAMP. Which turned out to be a wonderful choice. It’s got pdo_mysql support in its PHP build. It’s also a great way to do local development since you can easily turn it on, or restart. I would highly recommend it for development on your local machine.