Thursday, November 15, 2012

Overloading methods in Php: __call()

Just for the record I know that php does not support multiple classes to be extended and today while talking to a dear friend I thought this would work to sort of workaround this, and it did, for most cases I dont think this is very useful  but if you're in college this might come in handy for a homework or project:


<?php

class Mother
{ 
  public function func2() { return 'Mother knows best'; }
}

class Father
{
  private $_aClasses;
  public function __construct()
    $this->_aClasses = array( 'Mother' => new Mother); 
  }

  public function func1() { return 'func1 from Father'; }

  public function __call($sName, $aArguments)
  {
    foreach ($this->_aClasses as $oObj)
    {
      if (method_exists($oObj, $sName))
        echo $oObj->$sName(); 
      }
      else 
        var_dump($oObj); 
      }
    }
  }
}

$oF = new Father;
$oF->func2();
?>



This outputs "Mother knows best" even thought Father doesnt have a function func2().

Friday, June 29, 2012

Phpfox Developers: Correct way of sending mail (multiple languages)

Well we got a bug report today that at first seemed intimidating, the case was that in some mails being sent the script would not take into account the language of the receiver if it was a registered user. The first approach was to open the callback for that one case and scenario and fix it there, 3 lines of code edited no big deal, the problem is that it was a callback, meaning every module implemented, so 3 lines of code times 61 was too much to do by hand, luckily we have a built in method to change the language just for one phrase and the fix turned out to be site wide and implemented in less than 1 minute, here's the recap:

This code is wrong because it will not take the target user's language into account
Phpfox::getLib('mail')->to($aRow['user_id'])
->subject(Phpfox::getPhrase('module.var'))
->message(Phpfox::getPhrase('module.var'))

This next is correct:
Phpfox::getLib('mail')->to($aRow['user_id'])
->subject(array('module.var'))
->message(array('module.var'))

That is basically it, since you are passing the user_id in the ->to() function the mail library will pick up the language for that user, and by passing an array instead of the actual phrase the mail library will get the correct phrase, you can also include an array of parameters if you like as a second element in the array:

Phpfox::getLib('mail')->to($aRow['user_id'])
->subject(array('module.var', array('param1' => 'val1')))
->message(array('module.var', array('param2' => 'val2')))

and it will run the replacements as if you had done a getPhrase. Our fix was to Replace In Files all
 ->subject(Phpfox::getPhrase
with
->subject(array
and same for
->message.

Thursday, June 28, 2012

Backing up


Backing up is so important that every successful website has at least one person dedicated to this task.
If you have not yet defined your back up policy this post will help you.

Database Backups


There are specific tools for each database manager that you have (a database manager can be "MySQL", "PostgreSQL", "MSSQL"...). For now I will talk about the two kinds of backups:

Full Snapshot

This kind of backup takes your entire database and stores it in a flat file with instructions to delete tables when imported. It is a real copy of your database and is useful when moving your site to a new server, it also serves as the base for an incremental backup.

In MySQL there are two important tools that generate full snapshots: mysqldump and mysqlhotcopy. Since InnoDB is the default engine since MySQL 5.5 let me just give a quick introduction to mysqldump since mysqlhotcopy is meant for MyIsam tables. Keep in mind that these are server tools and you would execute them via console (SSH possibly).

mysqldump receives a number of parameters, not all are mandatory but the following will give you a full database dump that overwrites (deletes and re-creates) your existing data:

$ mysqldump --compact [db-name]

Another way of backing up your database is by directly copying the files. These files depend on the type of tables that you have and more detailed information can be found in the MySQL site.

Incremental Backup


Given a Full Snapshot backup you can store only the changes since the full backup, reducing the space and processing time needed, in mysql this is done using the binlog and not by chance this log is also used in Replication.

Restoring from a binary log file is very easy, for example:

$ mysqlbinlog binlogfile | mysql -u root -p

You can also export your binary log file to a flat file:

$ mysqlbinlog binlogfile > temporalfile.sql

File Backups


A full backup (tar or zip are very common) is also the easiest way to go, this however can lead to much larger storage requirements.


Generally speaking your files do not change that much, you upload an image and it will stay there, you will not update it and often times it will not be deleted until the end of time, a hard disk failure is also rare and if you do not manage your server chances are there are redundant backups (think RAID), I do not mean to ignore this kind of backups but in general terms a hard disk failure is easily mitigated up to a certain size.

The following command will compress the folder myFolder into the file myArchive.tar.gz
$ tar -zcf myArchive.tar.gz myFolder

The 'z' means to use GZip, the 'c' means to create an archive and the 'f' means to write it to a file.
Of course you also need to extract an archive, the following command will do just that:
$ tar -zxf myArchive.tar.gz

The 'x' parameter means to extract.

Another approach to backing up flat files is to use a subversion server, this is similar to the incremental backup and you can actually backup the files that make up for your database in SVN (although this is rather unconventional).

User Group Settings Check

If your custom phpfox module adds user group settings you may want to implement a validation for them, we added a way to run checks based on one bug report related to the custom fields, if you go to the AdminCP and manage settings for a user group, in the "Custom" module there's a setting "Custom field database table name?", this is the name of a table that must exist in the database already, we want to improve this whole routine but meanwhile the admin has to have the table created. So we added a callback in the module "Custom", this function receives an array with two indexes ("variable" and "value") and checks if the table exists. This is how that function looks like:
public function isValidUserGroupSetting($aVal)
{
  switch ($aVal['variable'])
  {
    case 'custom_table_name':
        return $this->database()->tableExists($aVal['value']);  
    default:
        return true;
  }
}

Remember that callback functions are to be placed in your callback.class.php file in your folder "service".

Monday, June 4, 2012

Phpfox: Database Errors

If you ever see the error "Cannot connect to the database", this could mean that your database user is not correct, that your database is not working or that the connection between your HTTP server and your database does not work.
This is not a bug in Phpfox, and you should contact your hosting company.

You can edit your database user in the file /include/setting/server.sett.php

Thursday, April 26, 2012

Phpfox: onReady with Ajax Browsing

Phpfox offers a site wide ajax browsing experience. This allows to load new pages and change the URL without actually going to another page. Clients save on resources since only needed components are loaded (things like the logo and menu are not requested).
This is pretty cool and makes for a smoother experience to the end user but some developers have had a hard time coupling their javascript routines into this model.

Meet $Behavior

$Behavior is a namespace that is triggered every time a page is loaded, even in ajax browsing mode. If your old JavaScript code looked like this:

$(document).ready(function() {
  // Your code here
});
You will have to change that to:
$Behavior.anyNameYouWant = function(){
  // Your code here
};
They are both equivalent except that with ajax browsing enabled it will trigger your "anyNameYouWant" function and not the JQuery one. Similarly this replaces the following:
$(function() {
 // Your code here
});
since that is the same as $(document).ready Even if site wide ajax browsing is disabled, the $Behavior namespace will be triggered, so you can safely code in $Behavior and not worry about site wide ajax browsing being enabled or disabled.

Saturday, April 21, 2012

NginX latest version in Ubuntu Server

The Ubuntu repositories are often outdated in comparison to the developer's release, today I wanted to install NginX in a recently installed Ubuntu Server but first I wanted to see how far behind the repository lagged, the following
~# apt-cache showpkg nginx

gave me the answer:
Package: nginx
Versions:
0.8.54-4 (/var/lib/apt/lists/gb.archive.ubuntu.com_ubuntu_dists_natty_universe_binary-amd64_Packages)

but going to the official site said the newest version was 1.0.15 (stable). Software versions are often split in 3 numbers, in this case the one in the ubuntu repository is "major version 0" and the one available from nginx is "major version 1", so the one from nginx seems more stable.
The next step was to add the NginX repository to Ubuntu so it would pick up the newer version:
~# sudo -s
~# nginx=stable
~# add-apt-repository ppa:nginx/$nginx

The first line there turns my user into root. The second one defines a variable, wherever I use $nginx it will be converted into "stable", this is used internally by the package installer as well. And the last of those lines actually adds the repository. This is what I got in return:
The program 'add-apt-repository' is currently not installed.  You can install it by typing:
apt-get install python-software-properties

No big deal, I just installed that package:
 ~# apt-get install python-software-properties

Since I had already sudo -s I did not need to use "sudo apt-get inst...". 42 KB later I had python-software-properties installed and running the last line (add-apt-repository...) went fine. Now the repository is added but we need to refresh the list of packages:
~# apt-get update

it will gargle some information about the packages its reading and eventually say its done.
Our last step is to actually install nginx:

~# apt-get install nginx

This gave me the next prompt:
After this operation, 2,707 kB of additional disk space will be used.
Do you want to continue [Y/n]?

Only 2707 kb! but each and every kb in that package is filled with pure awesomeness ;) type a y and press enter, it will do all the magic for you, even start nginx after it installed, and since its already running we can check the version with:

~# nginx -v
nginx version: nginx/1.0.15

Much better than 0.8.54.