You are on page 1of 4

My Issues with CodeIgniter (Updated: July 2013)

Form Validation is Hardwired to $_POST


The built-in library for validation uses global variable $_POST as data source and cannot be changed. So, if we want to test a form validation, we must mock the $_POST variable. It would be better to define the data source as parameter. Solution: use form validation only for POST request

Form Validation Can Only Use Controller's Method as Custom Callback Rule
If we want to apply a custom validation rule, we can use the Callback rule. But, Callback rule can only accept Controller's method. And that method must be publicly accessible. Remember that all publicly accessible method in Controller can also be accessed via browser (unnecessary route). It would be better if we can define any function/method as Callback rule. Solution: create a wrapper for form validation (Form_model class) that lets the use of method as validation

Form Validation Cannot Manually Trigger Error


Suppose we want to use any method other than Controller's method as additional rule. Normally, in that method we will do a checking and then trigger error in Form Validation object. But, Form Validation does not provide ability to manually trigger error. Solution: extend CI_Form_validation class, add set_error method

Form Validation Can Contain Only One Error Message Per Field
Suppose you define that a field has three validation rules. And the submitted value for that field violates all three rules. Form Validation will only show the error message for the first violation. Solution: either deal with it or extend CI_Form_validation

All Libraries are Designed Stateless or One-Time Use Only


Take Form Validation for example, the normal way to use it: give rules, do validation, get errors. Suppose I use Form Validation to validate two data, the supposed way to do it: 1. 2. 3. 4. 5. 6. 7. give rules for data 1 do validate data 1 get errors from data 1 empty rules/reset state give rules for data 2 do validate data 2 get errors from data 2

Unfortunately, there is no method for "empty rules" or "reset rules" or "reset the state of this library". Perhaps you are wondering "why not create another instance of Form Validation?", well CI does not work that way. Libraries and models are instantiated only once and then accessed globally. Solution: extend native libraries, add method to reset the state

CodeIgniter Encourages Anti-Patterns


Standard practice in CI is to use global state, this can be seen from the heavy use of get_instance() function. Get_instance() will return the front controller of current request, let's call this "CI instance". The normal way to load a model or library is to put the loaded model or library as a public member of the CI instance. Since CI was developed with PHP 4 in mind, it doesn't use many PHP 5 new features, especially OO-related. Solution: create our own autoloading, avoid get_instance() as much as you can

CodeIgniter Deliberately Sets PHP Max Execution Time


Look at this portion of code inside /system/core/Codeigniter.php i f( f u n c t i o n _ e x i s t s ( " s e t _ t i m e _ l i m i t " )= =T R U EA N D@ i n i _ g e t ( " s a f e _ m o d e " )= =0 ) { @ s e t _ t i m e _ l i m i t ( 3 0 0 ) ; } That code indicates that if PHP has no 's a f e _ m o d e ' option (deprecated since PHP 5.3), then it will call set_time_limit with a fixed amount of time. Problem Problem Problem Problem #1: #2: #3: #4: magic number 300 no way to configure this any value to m a x _ e x e c u t i o n _ t i m ein p h p . i n ifile is ignored this code still exists in the newest version (2.1.3)

Solution: delete that code, just like this pull request in CodeIgniter's repository

CodeIgniter Built-in Session Management Cannot Use PHP Native Session


CI has its own session management library which is cookie-based and can be stored in database. Unfortunately, this session management does not use PHP native session ($_SESSION). In the future CI 3, we can use native PHP session, but not in the current 2.x. Maybe you ask "so what?", I say "Why reinvent the wheel?". Besides that, native PHP session integrates better with many other PHP libraries (e.g. Using memcache as session storage). Solution: either deal with it or replace CI_Session (risky)

CodeIgniter 2 PDO Driver is Buggy


Look at these PDO bugs that my friend found in CI 2.1.x: 1. Missing backtick for MySQL, causing query failure. In Kaspay, there is a column named `delete` to flag whether a user is deleted or not. This column must be escaped with backtick (`) to avoid collision with delete reserved word. The issue was already posted in EllisLab GitHub, but no patch for 2.1.3, but for CI 3 instead. Link: https://github.com/EllisLab/CodeIgniter/issues/2229 2. PDO driver does not automatically enable transaction, even worse, the constructor disables transaction (line #84 pdo_driver.php). $ t h i s > t r a n s _ e n a b l e d=F A L S E ; But, the driver does not have the interface/public methods to re-enable transaction. This causes all transaction can not be rolled back. The issue was posted in EllisLab GitHub as well. Link: https://github.com/EllisLab/CodeIgniter/pull/2265 3. trans_commit() method contains error (pdo_driver.php): $ r e t=$ t h i s > c o n n > c o m m i t ( ) ;

The intention of the statement is to call commit() method provided by PDO class. But the PDO driver class does not have conn attributes, but conn_id instead. As in trans_begin() method: r e t u r n$ t h i s > c o n n _ i d > b e g i n T r a n s a c t i o n ( ) ; Khandar traced back the commit log in GitHub and found the error was made in 2011-08-23 (Yes, 1.5 year ago!) but without any complaints or feedback about this. Link: http://git.jorgenio.com/codeigniter/commits/ab347586ef289e960ab7cfad32574e526cdcce0b 4. reconnect() method contains error (pdo_driver.php): f u n c t i o nr e c o n n e c t ( ) { i f( $ t h i s > d b > d b _ d e b u g ) { r e t u r n$ t h i s > d b > d i s p l a y _ e r r o r ( ' d b _ u n s u p o r t e d _ f e a t u r e ' ) ; } r e t u r nF A L S E ; } The class does not have db attributes, but only db_debug. This error raises warning in strict mode. Nobody has issued this in EllisLab. My conclusion: people who use CodeIgniter almost never use the PDO driver (hence nobody complains) and almost any pull/bug fix request will be replied with "already fixed in development branch" (development branch = CodeIgniter 3). Solution: if you are okay with modifying framework code (pdo_driver.php) #1 add $ t h i s > _ e s c a p e _ c h a r=' ` ' ;in constructor #2 change the line to $ t h i s > t r a n s _ e n a b l e d=T R U E ; #3 change the line to $ r e t=$ t h i s > c o n n > c o m m i t ( ) ; #4 change the line to i f( $ t h i s > d b _ d e b u g ) If you are not okay with modifying framework code either don't use the PDO driver (use the old mysql[i]) or use third party library why not just extend this class? have you read the guide? N o t e :T h eD a t a b a s ec l a s s e sc a nn o tb ee x t e n d e do rr e p l a c e dw i t hy o u ro w n c l a s s e s .A l lo t h e rc l a s s e sa r ea b l et ob er e p l a c e d / e x t e n d e d . still insist? join the Dark Side, use this hack to be able extend the database driver

Did I Say CodeIgniter 2 PDO Driver is Buggy? I Meant Sucks


I also found another critical bug: after every query, the driver will try to get how many affected rows (see method _execute() in pdo_driver.php), the pseudo code: e x e c u t e _ q u e r y i f( q u e r yi saS E L E C T ) a f f e c t e d _ r o w s=c o u n t ( f e t c h A l l ( ) ) e x e c u t e _ q u e r ya g a i n e l s e a f f e c t e d _ r o w s=r o w C o u n t ( ) What makes this code buggy is the "i f( q u e r yi saS E L E C T ) " part: i f( i s _ n u m e r i c ( s t r i p o s ( $ s q l ,' S E L E C T ' ) ) ) What does that code mean? If there is a word "select" anywhere in the query, the driver thinks it is a SELECT, even though it might be INSERT/UPDATE/DELETE. When you try to f e t c h A l l ( ) an INSERT/UPDATE/DELETE query, it will return P D O E x c e p t i o n , which is what causes this bug. Beside that, this code also means that every SELECT query will be executed twice! What a performance killer.

The worst part? This only happens on the latest version (2.1.2-2.1.3), the older version doesn't have this issue. Maybe you are wondering why they need that i f ? Why not just use r o w C o u n t ( ) ? I think because it might not work for SELECT in some DBMS. Solution: extend pdo driver, take code from pdo driver in CI 3 method _ e x e c u t e ( )and a f f e c t e d _ r o w s ( )

One Does Not Simply Extend CI_Migration Class


So CodeIgniter has this cool relatively new feature called Migration. As with any other CI core classes, sometimes you need to add new methods. So, you do the usual: 1. 2. 3. 4. 5. Create file a p p l i c a t i o n / l i b r a r i e s / M Y _ M i g r a t i o n . p h p Write c l a s sM Y _ M i g r a t i o ne x t e n d sC I _ M i g r a t i o n{ Add some methods Write codes to test those new methods Voila, the code didn't work

Wait, what? Why? Because CI_Migration::__construct() forbid you to extend it #O n l yr u nt h i sc o n s t r u c t o ro nm a i nl i b r a r yl o a d i f( g e t _ p a r e n t _ c l a s s ( $ t h i s )! = =F A L S E ) { r e t u r n ; } What is the reason for this prohibition? The user guide didn't mention this. There are two people complaining about it and the best respond they get? "Seems pretty edge case. Just check the config." Didn't even tell why the restriction has to be there. Do you wanna know why? Migration has two components: the object that acts as migration (has up() and down() method) and the object that acts as migrator (can move version forward or backward). In CI, both objects have the same class: CI_Migration. I don't know why they design it that way, isn't a class is supposed to do one job only? Do they really know OOP? Isn't it supposed to be CI_Migrator and CI_Migration? The implication of this strange design is that restriction. If a class extends CI_Migration, its instance is considered a migration object. If an object is the instance of CI_Migration itself, it's considered the migrator object. Solution: when extending CI_Migration, copy-and-paste (ARGH!!) the whole constructor code because you can't use parent::__construct() (fixed in CI 3) Oh by the way, the Migration won't work perfectly with PDO driver because the PDO driver don't implement the drop table functionality (again, fixed only in CI 3).

The Only Fully Working Database Driver in CodeIgniter is Mysql[i] Driver


All the problems I mentioned before about how sucky PDO driver is, as it turns out, might also applied to other DB drivers in CodeIgniter. I said "might" because I haven't experienced it myself, but someone had issue with Postgre db forge. It closed 2 years ago and after I inspect the current CI code (2.1.2), the problem still exist (but the issue has been closed!). Previously though, Karol found similar issue with PDO db forge but in "modify_column" method. After doing a little digging, I found that the culprit for the error is the "_alter_table" method. Now, that issue with Postgre db forge is also originated from the "_alter_table" method. Hell, 80% of the code for all db forge (except mysql, mysqli, and cubrid) drivers are the same. So, those issues also happened in those drivers! This makes me conclude that Mysql[i] is the "golden child" of CI, it gets special treatment, they make sure that Mysql[i] driver will be fully working (perhaps because 99% of CI users use Mysql[i] driver). But, they abandon the other drivers. Since they abandon them, any bug with PDO driver might also exists in the other drivers. These issues are fixed in CodeIgniter 3 dev (as with most of the issues I mentioned above), but before they release CI 3, we are not allowed to use it. Solution: are you willing to fix all those bugs yourself? If you do, use the above hack to enable extending Database class, then fix them manually. If you don't, either stick to MySQL or don't use CodeIgniter.

You might also like