OEIC

Serialization issues in Zend_Acl

One of the features that originally drew me to the Zend Framework was the built-in ACL functionality. Most applications need to have some sort of user management, and I had been looking for a solid, easily extensible package to manage this so I didn’t have to spend a lot of time rolling my own. Unfortunately, I spent a significant amount of time today trying to diagnose why an ACL definition I’d built wasn’t working, so I thought I’d share my fix in case anyone else is having the same issue.

In the ACL Framework docs, it’s explicitly stated:

Storage of ACL data is therefore left as a task for the developer, since use cases are expected to vary widely for various situations. Because Zend_Acl is serializable, ACL objects may be serialized with PHP’s serialize() function, and the results may be stored anywhere the developer should desire, such as a file, database, or caching mechanism.

My approach was simple:

  1. Build the Zend_Acl object
  2. Serialize it
  3. Insert it into mysql as a string
  4. Retrieve, unserialize and query as needed

I did just that, but when I retrieved, unserialized and queried the ACL via the isAllowed() method, I got a Call to a member function on a non-object error. I ran a var_dump(), and the output sure looked like an object. I wanted to double-check that I had built a functional ACL object in the first place, so I replaced my database retrieved ACL object with the original code that I had used to define the ACL.

Sure, enough, my non-object error disappeared, and the ACL query returned the expected answer. Ok, somewhere in the serialization, insert to DB, select from DB and unserialize stack, the ACL was getting corrupted. I ran a simple object comparison between the the original ACL and the one retrieved from the database. Not too surprisingly, it returned false, meaning the two objects were different. Duh. I’m not even sure why I ran that check, in hindsight.

I wondered if serialize() was messing with the object for some reason, so I did a string comparison between the serialized original ACL and the serialized ACL retrieved from the database. The strings were equal in length, but strcasecmp() revealed that they were in fact different.

Each string looked identical when output to a browser, but when I viewed them in Notepad, it appeared that the original ACL contained some strange characters that displayed as tiny squares. These characters appeared as question marks in the database retrieved serialized object.

serialize.gif

It appeared that these characters were being replaced with question marks by the database (MySQL 4.1.21) because they weren’t part of the UTF8 character set. I never had any luck identifying these characters, and I didn’t serialize any other types of objects to see if the characters were unique to Zend ACL objects.

My solution was to base64_encode() the serialized ACL before sticking it into the database, to ensure a compatible character set. After retrieving, decoding and unserializing that string from the DB, the ACL worked like a charm. I’m not sure if this could be remedied by switching MySQL’s charset to ASCII or some other character set as I didn’t try that approach.

My environment consists of PHP 5.2.0, MySQL 4.1.21 and Zend Framework 1.0 RC1, if you’re curious.

UPDATE: Further research on this issue led me to this comment and bug report on the PHP site. It seems that this issue stems from objects that have private and protected properties. The bug report says that this issue had been resolved in PHP 5.0.5, so perhaps my installation is the culprit.

5 Comments     Jump to comment form | comments rss | trackback uri

1
eKini Web Development Blog
October 2, 2007 / 11:45 pm

Hello,
thanks for this post… i am trying to learn Zend_Acl….
in your approach, you would serialize and then base64_encode() the ACL Object and then insert it into the DB.
is my assumption correct?
that the serialized ACL object in the DB will be side-by-side with the username/user ID? So that when the user logs in again, i would retrieve the ACL Object and use it again?
with that assumption, i have some questions. What if i wanted to update the ACL for all “members”, how would I do that? when the ACL Object is already stored as string in the database? won’t the ACL Object contain the old permissions?
I am confused on the way I should handle Zend_ACL…
Maybe you could post a step-by-step procedure of your approach? something like a flow-chart but in textual form :)

again, thanks for this post!

2
steve
October 3, 2007 / 3:38 pm

Your assumption is indeed correct, but as mentioned at the end of the post, it might not be necessary to base64_encode() your serialized ACL object. Only testing in your environment will confirm if it is necessary or not, though the overhead of encoding/decoding might not be so much.

You’re also correct that in my case, I have a serialized ACL object in the database along side each user ID. However, this approach isn’t appropriate for each application. For instance, if you wanted to update the resources available for each member, you would have to update the ACL object stored in each row of your database by rebuilding the ACL object in PHP, then doing a SQL UPDATE. If you have a static, defined list of resources and roles, you may consider storing your ACL as a single row in a “Permissions” database table, or in a text file, or some other persistent state. My approach might not be the best for every application, but it fit my needs.

Perhaps I’ll write up a tutorial on Zend_ACL that is more design focused, but I’d recommend taking a look at Simon Mundy’s nuts and bolts tutorial here: http://devzone.zend.com/node/view/id/1665

3
John Reader
January 25, 2008 / 7:13 pm

I wish I had read this earlier in 2007. This bug bit a website and took hours to nail down. base64 to the rescue!

4
itlong
March 4, 2008 / 1:21 am

where the code,and I can’t read it.

5
網站製作學習誌 » [Web] 連結分享
November 24, 2009 / 10:44 pm

[…] OEIC » Serialization issues in Zend_Acl […]

Say what?

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <code> <em> <i> <strike> <strong>





About this entry

Categories