Pablo Viquez Blog

Mi vida y cosas relacionadas

Skip to: Content | Sidebar | Footer

Zend Framework Documentation

12 March, 2010 (02:09) | PHP | By: Pablo Viquez

I’ve been wanting to do this for quite some time now, so here it’s. Go to the downloads

As you might now, you can view and download the Zend Framework reference manual from the Zend Framework site and download it from the download section, however what I wanted was the Windows compiled version of it (CHM file). In order to get this version you need to compile the documentation, after running into some small issues, I manage to do it, and to save you some work here it’s :D

By the way, the problem I had was parsing one XML file. Zend Framework issue tracker reports that the issue was fixed but the SVN tag have the error, anyway if you try to create the documentation from the SVN repository for the version 1.10.2, you will encounter some parsing errors, in order to fix those, you can do this:

Line 161
From:

<title type="html"><![CDATA[All Your Base Are Belong To Us]]></title>

To:

<title type="html"><![CDATA[All Your Base Are Belong To Us]]&gt;</title>

Line 163
From:

<![CDATA[Exposing the difficultly of porting games to English.]]>

To:

<![CDATA[Exposing the difficultly of porting games to English.]]&gt;

Line 177
From:

The example is long enough as is ;;).]]>

To:

The example is long enough as is ;;).]]&gt;

IMPORTANT, since you escaped the XML file, you also need to revert it in the generated HTML file.

Anyway, if you want you can just download both files here: Zend_Feed_Writer.xml and zend.feed.writer.html

Zend Framework Documentation – CHM Format

I compile the CHM format for English and Spanish, the spanish version is incomplete so you might find some parts in english.

English
Español

Información para el archivo en español

La documentación en español está incompleta y debido a esto, se econtrará muchas secciones de la guía en inglés.

 

 

Zend_Log, FirePHP and Zend_Application. How to

25 November, 2009 (16:23) | PHP, debug, tech | By: Pablo Viquez

I wanted to enable logging of exceptions to my PHP log file and also display them using FireBug.

On a standard setup of Zend Framework, the Zend error handler plugin (Zend_Controller_Plugin_ErrorHandler) enable by default and it was designed for:

  • Errors due to missing controllers or actions
  • Errors occurring within action controllers

I wanted to keep using the error handler plugin and didn’t want to log the exceptions by using: Zend_Controller_Front::throwExceptions() or Zend_Controller_Response_Abstract::renderExceptions() or any other way since eventually might get complicated, besides, I think that the error handler plugin works fine and if it gets updated in the future, I won’t have to do a major refactor.

So this is how I did it:

Create the Zend Log Object

Using Zend_Application can be very helpful here, because you can init the logger and automatically store the object in the registry, making available to the controllers later on.

Summary, if you want an object created on the boostrap class, to be available on the controllers later, you need to return it from the init method, in this case, we’re initializing the Zend_Log, so we need to return the object.

<?php
class App_Bootstrap extends Zend_Application_Bootstrap_Bootstrap
{

    /**
     * Initializes the logging on the application
     *
     * We're using 2 ways for logging exceptions:
     * 1. PHP Error log file.
     * 2. Firebug for Development environments only.
     *
     * @return Zend_Log
     */
    protected function _initLogger()
    {
        // Create the Zend_Log object
        $logger = new Zend_Log();

        // Create the resource for the error log file
        // if you dont want to use the error suppressor "@"
        // you can always use: is_writable
        // http://php.net/manual/function.is-writable.php
        $stream = @fopen(ini_get('error_log'), 'a');
        if ($stream) {
            $stdWritter = new Zend_Log_Writer_Stream($stream);
            $stdWritter->addFilter(Zend_Log::DEBUG);
            $stdWritter->addFilter(Zend_Log::INFO);
            $logger->addWriter($stdWritter);
        }

        // Create the Firebug writter - Development only
        if ($this->_application->getEnvironment() != 'production') {
            // Init firebug logging
            $fbWriter = new Zend_Log_Writer_Firebug();
            $logger->addWriter($fbWriter);
        }

        return $logger;
    }

I have now the log object but I’m not logging anything yet, so I need to implement the logging part.

Log the Exception

For this part, I thought in 2 ways to do it:

  1. Extend the error handler plugin and log errors there.
  2. Log the errors on the error controller.

I choose the second one for several reasons:

  1. Easier.
  2. If the error handler changes somehow, you dont have to change your code.
  3. Extending the error plugin, might lead to repeated code and eventually deprecated code.

By default, Zend_Controller_Plugin_ErrorHandler will forward to ErrorController::errorAction() in the default module.

Now in order to retrieve a resource created in the bootstrap we need to access the bootstrap registered in the front controller, and from there we can get our logger:

// The method _initLogger on the class App_Bootstrap
// returns a Zend_Log object that is available
// on the Zend_Registry. To retrieve it we need to request the
// bootstrap from the Front controller and then get the logger.
$boot = $this->getInvokeArg('bootstrap');
if ($boot->hasResource('logger')) {
    $log_object = $boot->getResource('logger');
}

So using the Zend Framework default error controller (the one provided on the reference), with the logging will be something like this:

class ErrorController extends Zend_Controller_Action
{
    /**
     * Error action. This method is called by
     * Zend_Controller_Plugin_ErrorHandler
     *
     * @see Zend_Controller_Plugin_ErrorHandler
     * @return void
     */
    public function errorAction()
    {
        $errors = $this->_getParam('error_handler');

        // Log the Error.
        $boot = $this->getInvokeArg('bootstrap');
        if ($boot->hasResource('logger')) {
            $boot->getResource('logger')->err($errors->exception);
        }

        // Default error handling...
        switch ($errors->type) {
            case Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_CONTROLLER:
            case Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_ACTION:

                // 404 error -- controller or action not found
                $this->getResponse()->setHttpResponseCode(404);
                $this->view->message = 'Page not found';
                break;
            default:
                // application error
                $this->getResponse()->setHttpResponseCode(500);
                $this->view->message = 'Application error';
                break;
        }

        $this->view->exception = $errors->exception;
        $this->view->request   = $errors->request;
    }
}

Result

The final result looks like this:

Firefox with Firebug enabled:

Firefox Screenshot with Firebug enabled

PHP error log file:

[pviquez /usr/home/pviquez]$ cat php_error.log
2009-11-25T15:23:19-06:00 ERR (3): exception 'Zend_Exception' with message 'The logging is working!' in /usr/home/pviquez/app/deploy/application/modules/admin/controllers/IndexController.php:33
Stack trace:
#0 /usr/home/pviquez/app/deploy/library/Zend/Controller/Action.php(513): Admin_IndexController->indexAction()
#1 /usr/home/pviquez/app/deploy/library/Zend/Controller/Dispatcher/Standard.php(289): Zend_Controller_Action->dispatch('indexAction')
#2 /usr/home/pviquez/app/deploy/library/Zend/Controller/Front.php(946): Zend_Controller_Dispatcher_Standard->dispatch(Object(Zend_Controller_Request_Http), Object(Zend_Controller_Response_Http))
#3 /usr/home/pviquez/app/deploy/library/Zend/Application/Bootstrap/Bootstrap.php(77): Zend_Controller_Front->dispatch()
#4 /usr/home/pviquez/app/deploy/library/Zend/Application.php(346): Zend_Application_Bootstrap_Bootstrap->run()
#5 /usr/home/pviquez/app/deploy/public/index.php(23): Zend_Application->run()
#6 {main}

References

Export Excel Spreadsheets using Zend Framework

24 August, 2009 (14:04) | PHP, Web Development, tech | By: Pablo Viquez

Last week, I had to allow the user to export a given report into an MS Excel file format.

The application uses Zend Framework 1.9.1 and so far ZF does not support for “Office” formats, so after searching for a nice implementation, I found a PEAR module called Spreadsheet Excel Writter, which looked pretty good, it had very good documentation and the code was clean and well structured so I wanted to give it a shot.

1. PEAR Setup

I used the web interface for the PEAR setup which worked pretty good! (Not covering PEAR installation here).

If you want more info on how to install PEAR, go here: http://pear.php.net/manual/en/installation.getting.php and for the web setup: http://pear.php.net/go-pear

ONCE INSTALLED, REMEMBER TO ADD THE PEAR PATH TO YOUR INCLUDE PATH

2. Following the MVC pattern.

Model View Controller

Model View Controller Diagram

I love the architecture following MVC (Model View Controller) and if I follow the MVC pattern, excel file will go as VIEW, this because the data is being presented an excel file.

Also, the controller does not care which format does the info gets display, the controller should care about manipulating modules, getting the data, controlling the flow of the application not about the presentation layer.

So what did I do?

Zend Framework offers a nice feature called “Context Switch”. This is an action helper that detects requested output and calls the specific view for the required format.

In my case, I wanted to enable this feature to the user controller, which had 3 actions:

  • user/index
  • user/new
  • user/report

Now, I wanted to give the option to export the data as excel only for the “report” action, so I did this on the controller init method:

class UserController extends Zend_Controller_Action
{
    /**
     * Initializes the controller
     *
     * @return void
     */
    public function init()
    {
        // Optional added for consistency
        parent::init();

        // Excel format context
        $excelConfig =
            array(
                'excel' => array(
                    'suffix'  => 'excel',
                    'headers' => array(
                        'Content-type' => 'application/vnd.ms-excel')),
            );

        // Init the Context Switch Action helper
        $contextSwitch = $this->_helper->contextSwitch();

        // Add the new context
        $contextSwitch->setContexts($excelConfig)

        // Set the new context to the reports action
        $contextSwitch->addActionContext('report', 'excel')

        // Initializes the action helper
        $contextSwitch->initContext();
    }

    public function indexAction() { /* ... */ }
    public function newAction() { /* ... */ }
    public function reportAction() { /* ... */ }
}

What this code does is that it tells the controller to search on the parameters (GET/POST) for token “format” and the value “excel”. In other words, If the report action get requested like this:

/user/report?format=excel or /user/report/format/excel instead of loading the view: report.phtml will load the view report.excel.phtml and here is where the magic happens!

In the setup of the Context Switch, the “suffix” is what will be appended to the view file.

The report action, just gets the report and sets a variable on the view so it’s accesible as follow:

class UserController extends Zend_Controller_Action
{
    public function init() { /* ... */ }
    public function indexAction() { /* ... */ }
    public function newAction() { /* ... */ }

    /**
     * Report action
     *
     * @return void
     */
    public function reportAction()
    {
        // Proof of concept
        // Lets say that the result have the following structure
        //
        // array(
        //     [USER ID] => array(
        //                      'name'  => 'Pablo Víquez',
        //                      'email' => 'email@domain.com',
        //                  ),
        //     [USER_ID] => array(...),
        //     ...
        // )
        $this->view->users = User_Model_Name::getReport();
    }
}

Now the view…

I need to have 2 files for this action:

  • report.phtml – Output will be regular HTML
  • report.excel.phtml – Output will be an MS Excel spreadsheet

report.phtml

This is the HTML format.

<h1>Users report</h1>

<table>
    <thead>
        <tr>
            <th>User Id</th>
            <th>Name</th>
            <th>Email</th>
        </tr>
    </thead>
<!--
    Variable set on the controller, if there's no data to display
    the count will be 0.
-->
<?php if(count($this->users) > 0) : ?>
<?php foreach ($this->users as $userId => $user) : ?>
    <tr>
        <td><?php echo $userId; ?></td>
        <td><?php echo $user['name']; ?></td>
        <td><?php echo $user['email']; ?></td>
    </tr>
<?php endforeach; ?>
<?php endif; ?>
</table>

report.excel.phtml


// Change error reporting for compatibility
// Spreadsheet Excel Writter was built using PHP4,
// so there's a lot of DEPRECATED notices
error_reporting(E_ERROR | E_WARNING | E_PARSE);

/**
 * PEAR package
 *
 * @link http://pear.php.net/package/Spreadsheet_Excel_Writer
 * @see PEAR/Spreadsheet/Excel/Writer.php
 */
require_once 'Spreadsheet/Excel/Writer.php';

// Lets define some custom colors codes
define('CUSTOM_DARK_BLUE', 20);
define('CUSTOM_BLUE', 21);
define('CUSTOM_LIGHT_BLUE', 22);
define('CUSTOM_YELLOW', 23);
define('CUSTOM_GREEN', 24);

// First, we create a Workbook
$workbook = new Spreadsheet_Excel_Writer();

// Add one sheet, called: Users Report
$worksheet = &$workbook->addWorksheet('Users Report');

// Create the custom colors on our new workbook
// This function takes 4 params:
//    - Code index [1 to 64]
//    - RGB colors (0-255)
$workbook->setCustomColor(CUSTOM_DARK_BLUE, 31, 73, 125);
$workbook->setCustomColor(CUSTOM_BLUE, 0, 112, 192);
$workbook->setCustomColor(CUSTOM_LIGHT_BLUE, 184, 204, 228);
$workbook->setCustomColor(CUSTOM_YELLOW, 255, 192, 0);
$workbook->setCustomColor(CUSTOM_GREEN, 0, 176, 80);

// Lets hide gridlines
$worksheet->hideScreenGridlines();

// Lets create some custom styles
$formatHeader = &$workbook->addFormat();
$formatHeader =
    &$workbook->addFormat(
        array('Size'    => 16,
              'VAlign'  => 'vcenter',
              'HAlign'  => 'center',
              'Bold'    => 1,
              'Color'   => 'white',
              'FgColor' => CUSTOM_DARK_BLUE));

$formatReportHeader =
    &$workbook->addFormat(
        array('Size'     => 9,
              'VAlign'   => 'bottom',
              'HAlign'   => 'center',
              'Bold'     => 1,
              'FgColor'  => CUSTOM_LIGHT_BLUE,
              'TextWrap' => true));

$formatData =
    &$workbook->addFormat(
        array(
            'Size'   => 8,
            'HAlign' => 'center',
            'VAlign' => 'vcenter'));

/**
 * First, format the worksheet, adding the headers
 * and row/columns custom sizes
 */

// Create a nice header with a dark blue background
// The function setRow takes 3 parameters:
//    - row index
//    - row height
//    - Format to apply to row [Optional]
$worksheet->setRow(0, 11, $formatHeader);
$worksheet->setRow(1, 46, $formatHeader);
$worksheet->setRow(2, 11, $formatHeader);

// Set the size of the columns
// The function setColumn takes 5 params:
//     - First column
//     - Last column
//     - Column Width
//     - Format [Optional, default = 0]
//     - Hidden [Optional, default = 0]
$worksheet->setColumn(0, 0, 7); // User Id, shrink it to 7
$worksheet->setColumn(1, 1, 12); // Name, set the width to 12
$worksheet->setColumn(1, 1, 15); // Email, set the width to 15

/**
 *
 * Once we have the format ready, add the text to the spreadsheet
 *
 */
// Write a text header
$worksheet->write(1, 1, 'Users report', $formatHeader);

// Create the header for the data starting @ row 4
$indexCol = 0;
$indexRow = 4;
$worksheet->write($indexRow, $indexCol++, 'User Id', $formatReportHeader);
$worksheet->write($indexRow, $indexCol++, 'Name', $formatReportHeader);
$worksheet->write($indexRow, $indexCol++, 'Email', $formatReportHeader);

$indexRow++;   // Advance to the next row
$indexCol = 0; // Start @ column 0

// Print the report data
if(count($this->users) == 0) {
    // No data
    $worksheet->write(
        $indexRow,
        $indexCol,
        'No data to display',
        $formatData);

} else {
    // Write the data
    foreach ($this->users as $userId => $user) {
        $worksheet->writeNumber(
            $indexRow,
            $indexCol++,
            $userId,
            $formatData);

        $worksheet->write(
            $indexRow,
            $indexCol++,
            $user['name'],
            $formatData);

        $worksheet->write(
            $indexRow,
            $indexCol++,
            $user['email'],
            $formatData);

        // Advance to the next row
        $indexRow++;
    }
}

/**
 *
 * Response with the excel file
 *
 */

// Sends HTTP headers for the Excel file.
$workbook->send('report.xls');

// Calls finalization methods.
// This method should always be the last one to be called on every workbook
$workbook->close();

Proxima reunión

5 August, 2009 (16:54) | General, PHP, costa rica php | By: Pablo Viquez

Ya se anunció la próxima reunión del grupo de PHP. (Ver anuncio)

Esta es la información del evento:

Donde: Auditorio Universidad Latina de Costa Rica

Cuando: Martes 11 de Agosto, 7:00pm

reunion_2009-08-11

El tema de Unit Testing e Integración Continua la verdad está muy bueno, recomendado.

How to use json_encode with ISO-8859-1 data – Part2

31 July, 2009 (12:04) | PHP, Web Development, iso 8859-1, utf-8 | By: Pablo Viquez

To continue with the previous post.

Problem: Function json_encode does not support ISO-8859-1 encoded data.

One solution that I did, in order to preserve the character set was to encode the
data before using the json_encode function to use just A-Z, a-z and 0-9 characters,
instead of sending text with accents or symbols.

One encoding that fits perfectly in this schema, is Base64 Content-Transfer-Encoding. (see base 64 explanation below)

This leads me to the solution: Encode the ISO-8859-1 using base64 and decoded in the client using JavaScript.

Now, this lead me to another issue, what’s the algorithim to implement the base64_decode function in JavaScript?

Luckly enough, I was looking at the site: http://phpjs.org/ which ported most of the PHP functions to JavaScript and problem solved!

Download the demo files here

Solution

So my solution will look like this (using the demo files from my previous post):

prueba_ansi.php

<?php
$id =
    base64_encode(
        utf8_encode('iso-8859-1'));
$name =
    base64_encode(
        utf8_encode('Pablo Víquez - This is an ISO-8859-1 encoded text'));
$notes =
    base64_encode(
        utf8_encode('Test with JSON encoding. á é í ó ú, ñ, Ñ.'));

$customer =
    array(
        'id'    => $id,
        'name'  => $name,
        'notes' => $notes
);

echo json_encode($customer);

As you can see, I used 2 functions to encode the data: base64_encode and utf8_encode.

I used these 2, mostly because the JavaScript implementation of base64_decode asumes
that the data is UTF-8 encoded, by doing base64_encode(utf8_encode(‘iso-8859-1′))
I’m acctually first encoding the data to be UTF-8 first and then encoding it using Base64.

base64_encode
Encodes data with MIME base64, and has the following description:

string base64_encode ( string $data )

utf8_encode
Encodes an ISO-8859-1 string to UTF-8, and has the following description:

string utf8_encode  ( string $data  )

Client Side

I used JQuery to retrieve the JSON data, and the phpjs.org implementation for the
base64_decode and utf8_decode functions.

index.html

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>JSON Consumer</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<script type="text/javascript" src="http://jqueryjs.googlecode.com/files/jquery-1.3.2.min.js"></script>
<script type="text/javascript">
$(document).ready(function(){
    $("#query_data_iso").click(
        function(){
            getIsoData();
        }
    );

    $("#query_data_utf8").click(
        function(){
            getUtfData();
        }
    );
});

function getUtfData() {
    $.ajax({
        type:       "GET",
        dataType:   "json",
        url:        "prueba_utf8.php",
        success:    function(response){
            $("#customer_data_id").html(response.id);
            $("#customer_data_name").html(response.name);
            $("#customer_data_notes").html(response.notes);
        },
    });
}

/**
 * Gets a JSON response from the server.
 * Expectes a base64 encoded response with: id, name and notes all base64 encoded.
 */
function getIsoData() {
    $.ajax({
        type:       "GET",
        dataType:   "json",
        url:        "prueba_ansi.php",
        success:    function(response){
            $("#customer_data_id").html(base64_decode(response.id));
            $("#customer_data_name").html(base64_decode(response.name));
            $("#customer_data_notes").html(base64_decode(response.notes));
        },
    });
}

/**
 * Decodes string using MIME base64 algorithm
 * @see http://phpjs.org/functions/base64_decode
 */
function base64_decode( data ) {
    var b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
    var o1, o2, o3, h1, h2, h3, h4, bits, i = 0, ac = 0, dec = "", tmp_arr = [];

    if (!data) {
        return data;
    }

    data += '';

    do {  // unpack four hexets into three octets using index points in b64
        h1 = b64.indexOf(data.charAt(i++));
        h2 = b64.indexOf(data.charAt(i++));
        h3 = b64.indexOf(data.charAt(i++));
        h4 = b64.indexOf(data.charAt(i++));

        bits = h1<<18 | h2<<12 | h3<<6 | h4;

        o1 = bits>>16 & 0xff;
        o2 = bits>>8 & 0xff;
        o3 = bits & 0xff;

        if (h3 == 64) {
            tmp_arr[ac++] = String.fromCharCode(o1);
        } else if (h4 == 64) {
            tmp_arr[ac++] = String.fromCharCode(o1, o2);
        } else {
            tmp_arr[ac++] = String.fromCharCode(o1, o2, o3);
        }
    } while (i < data.length);

    dec = tmp_arr.join('');
    dec = this.utf8_decode(dec);
    return dec;
}

/**
 * Converts a UTF-8 encoded string to ISO-8859-1
 * @see http://phpjs.org/functions/utf8_decode
 */
function utf8_decode ( str_data ) {
    var tmp_arr = [], i = 0, ac = 0, c1 = 0, c2 = 0, c3 = 0;

    str_data += '';

    while ( i < str_data.length ) {
        c1 = str_data.charCodeAt(i);
        if (c1 < 128) {
            tmp_arr[ac++] = String.fromCharCode(c1);
            i++;
        } else if ((c1 > 191) && (c1 < 224)) {
            c2 = str_data.charCodeAt(i+1);
            tmp_arr[ac++] = String.fromCharCode(((c1 & 31) << 6) | (c2 & 63));
            i += 2;
        } else {
            c2 = str_data.charCodeAt(i+1);
            c3 = str_data.charCodeAt(i+2);
            tmp_arr[ac++] = String.fromCharCode(((c1 & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
            i += 3;
        }
    }

    return tmp_arr.join('');
}
</script>

</head>

<body>
    <h1>ISO 8859-1, JSON consumer</h1>

    <p>
        <a href="#" id="query_data_iso">Query for ISO-8859-1 data</a> |
        <a href="#" id="query_data_utf8">Query for UTF-8</a>
    </p>
    <table border="1">
        <tr>
            <td>Id</td>
            <td>Name</td>
            <td>Notes</td>
        </tr>
        <tr>
            <td><div id="customer_data_id"></div></td>
            <td><div id="customer_data_name"></div></td>
            <td><div id="customer_data_notes"></div></td>
        </tr>
    </table>
</body>
</html>

Downsize

The downsize to this solution will be the size of the encoded transfer, this because Base64-encoded data takes about 33% more space than the original data.

References

Base64 Content-Transfer-Encoding

http://tools.ietf.org/html/rfc2045

Normally, many media types which could be usefully transported via email are
represented, in their “natural” format, as 8bit character or binary data.
Such data cannot be transmitted over some transfer protocols.

For example, email. The SMTP (simple mail transfer protocol) restricts mail
messages to 7bit US-ASCII data with lines no longer than 1000 characters
including any trailing CRLF line separator.

PHP JS

  • base64_decode – http://phpjs.org/functions/base64_decode
  • utf8_decode – http://phpjs.org/functions/utf8_decode

How to use json_encode with ISO-8859-1 data – Part1

17 July, 2009 (13:51) | PHP, Web Development, debug, iso 8859-1, utf-8 | By: Pablo Viquez

Download the demo files

While I was looking at some AJAX calls, I started to have a problem, for some reason, when I tried to query a JSON service I did using JQuery, the result was null for some fields.

Going a little deeper, I notice that the records from the DB were OK, and the JavaScript was OK to, so what was the problem? The JSON Encode!

So take for instance this code:

$customer =
    array(
        'id'    => 1,
        'name'  => 'Pablo Víquez',
        'notes' => 'Pruebas de encoding con JSON. á é í ó ú, ñ, Ñ'
);

echo json_encode();

If I save it as a ISO-8859-1, the result is the following:

{"id":1,"name":null,"notes":null}

Now, using the same code, but saving the PHP file as UTF-8 I got this result:

{"id":1,"name":"Pablo V\u00edquez","notes":"Pruebas de encoding con JSON. \u00e1 \u00e9 \u00ed \u00f3 \u00fa, \u00f1, \u00d1"}

The problem that I had was that the site was built using ISO 8859-1 not UTF-8, and changing it to UTF-8 is not an option, andn the AJAX call must return a JSON response.

json_encode documentation

string json_encode ( mixed $value [, int $options= 0 ] )

  • $value: The value being encoded. Can be any type except a resource.
    This function only works with UTF-8 encoded data.
  • $options (PHP 5.3 ONLY): Bitmask consisting of JSON_HEX_QUOT, JSON_HEX_TAG, JSON_HEX_AMP, JSON_HEX_APOS, JSON_FORCE_OBJECT. Defaults to 0.

 

PHP 5.3 with improved Type Hinting and type casting

9 July, 2009 (09:58) | PHP, tech | By: Pablo Viquez

From Illia Alshanetsky blog post:

There has been a lot of comments both on this blog and the internals list. There seems to be a fairly large group of core developers who like the idea as well as surpassingly large support base on the user level too (wow, didn’t think that this many people want type hinting). Unfortunately, there have also been, as is typically on the internals list a few people complaining for the sake of complaining. Their arguments have ranged from type hinting is against PHP’s loosely typed nature and people will mis-use it and make PHP into something that it is not, to I don’t need or will use it, so no one should get it.

…Here is the quick changelog.

  1. Added support for “object” type hint
  2. Modified the patch not to break binary compatibility so you can now use patched PHP without having to re-compile your extensions or having issues with binary ones.
  3. Added full reflection support, which I appropriated from Felipe’s earlier work on type hinting
  4. Added support for type casting, where by you can do things like this function a((int)$foo), which will force PHP to cast the value of $foo to an integer
  5. Added tests, which again I partially appropriated from Felipe’s earlier work.

The types that could be used (according to the proposed patch) are:

Boolean String Integers Floats Others
  • bool
  • boolean
  • string
  • binary
  • unicode
  • int
  • integer
  • long
  • real
  • double
  • float
  • resource
  • numeric
  • scalar
  • object

So, how do that will look like? Here some examples of how this will look like:

Type Casting on function definition:

function printMe((int) $value) {
    var_dump($value);
}

// Output:
// int(50)
printMe(50);

// Output:
// int(123)
printMe('123');

// Output:
// int(0)
printMe('Testing');

// Output:
// int(0)
printMe(null);

Or using String as type casting

function printMeAgain((string) $value) {
    var_dump($value);
}

// Output:
// string(2) "50"
printMeAgain(50);

// Output:
// string(3) "123"
printMeAgain('123');

// Output:
// string(7) "Testing"
printMeAgain('Testing');

// Output:
// string(0) ""
printMeAgain(null);

Type Hinting

function test_int(int $a = 1) {
    var_dump($a);
}

// Output:
// int(1)
test_int();

// Output:
// int(123)
test_int(123);

// Output:
// Catchable fatal error: Argument 2 passed to test_int()
// must be of the type integer, string given
test_int("123");

With doubles:

function test_double(real $a) {
    var_dump($a);
}

// Output:
// float(1)
test_double(1);

// Output:
// float(1.123)
test_double(1.123);

// Output:
// Catchable fatal error: Argument 1 passed to
// test_double() must be of the type double,
// string given.
test_double("123");

With Strings:

function test_string(string $a) {
    var_dump($a);
}

// Output:
// string(10) "Hola Mundo"
test_double("Hola Mundo");

// Output:
// Catchable fatal error: Argument 1 passed to
// test_string() must be of the type string,
// int given
test_double(123);

// Output:
// Catchable fatal error: Argument 1 passed to
// test_string() must be of the type string,
// null given
test_str(null);

Cannes Festival Touchwall

26 June, 2009 (10:15) | schematic | By: Pablo Viquez

I wanted to share another video on the Touchwall.

It was made for the Cannes Lions Festival which is the largest advertising and PR conference of the year.

Schematic Touchwall

17 June, 2009 (12:10) | schematic, tech | By: Pablo Viquez

I’m super happy for my colleagues on the success of the biggest touch wall ever!

Move foreign keys from one table to another in Oracle

15 June, 2009 (09:58) | tech | By: Pablo Viquez

I needed to switch all foreign keys from one table to another using PL/SQL in Oracle. This was the result:

Necesitaba un script para pasar los foreign keys de una tabla a otra en Oracle, al final este es el resultado:

/**
 * Modifies all references to entity_old and switch them to entity
 *
 * Process
 *  1. Disable Foreign Keys
 *  2. Drop foreign key
 *  3. Create the foreign key, pointing to the new location
 */

var v_old_table varchar2(100);
var v_new_table varchar2(100);
var v_sql varchar2(500);
var v_sql_delete varchar2(500);

exec :v_old_table := 'OLD_TABLE_NAME_HERE';
exec :v_new_table := 'NEW_TABLE_NAME_HERE';

SET SERVEROUTPUT ON;
BEGIN
    FOR row_entity IN (SELECT ac.CONSTRAINT_NAME,
                              ac.CONSTRAINT_TYPE,
                              ac.TABLE_NAME,
                              ac.R_CONSTRAINT_NAME,
                              ac.STATUS,
                              ac.DELETE_RULE,
                              cc.COLUMN_NAME,
                              sr.COLUMN_NAME AS COLUMN_SOURCE
                         FROM ALL_CONSTRAINTS ac,
                              USER_CONS_COLUMNS cc,
                              USER_CONS_COLUMNS sr
                        WHERE ac.CONSTRAINT_NAME = cc.CONSTRAINT_NAME
                          AND ac.R_CONSTRAINT_NAME = sr.CONSTRAINT_NAME
                          AND ac.CONSTRAINT_TYPE = 'R'
                        AND ac.R_CONSTRAINT_NAME IN (SELECT CONSTRAINT_NAME
                                                       FROM ALL_CONSTRAINTS
                                                      WHERE CONSTRAINT_TYPE IN ('P','U')
                                                       AND TABLE_NAME = :v_old_table))
    LOOP
        BEGIN
            -- Disable the foreign key IF is enable
            IF row_entity.STATUS = 'ENABLED' THEN
                :v_sql := 'ALTER TABLE ' || row_entity.TABLE_NAME ||
                  ' MODIFY CONSTRAINT ' || row_entity.CONSTRAINT_NAME ||
                  ' DISABLE';

                -- Print SQL Statement
                DBMS_OUTPUT.PUT_LINE(:v_sql || ';');

                EXECUTE IMMEDIATE :v_sql;
            END IF;

            IF row_entity.DELETE_RULE = 'CASCADE' THEN
                :v_sql_delete := ' ON DELETE CASCADE';
            ELSE
                :v_sql_delete := '';
            END IF;

            -- Drop the table reference
            :v_sql := 'ALTER TABLE '|| row_entity.TABLE_NAME ||
                    ' DROP CONSTRAINT ' || row_entity.CONSTRAINT_NAME;

            DBMS_OUTPUT.PUT_LINE(:v_sql || ';');
            EXECUTE IMMEDIATE :v_sql;

            -- Re-create the table reference
            :v_sql := 'ALTER TABLE '|| row_entity.TABLE_NAME ||
                    ' ADD CONSTRAINT ' || row_entity.CONSTRAINT_NAME ||
                    ' FOREIGN KEY (' || row_entity.COLUMN_NAME || ')' ||
                    ' REFERENCES ' || :v_new_table || ' (' || row_entity.COLUMN_SOURCE || ')' ||
                    :v_sql_delete;

            DBMS_OUTPUT.PUT_LINE(:v_sql || ';');
            EXECUTE IMMEDIATE :v_sql;
        END;
    END LOOP;
END;

/

show errors;