Thursday, March 26, 2009

[PHP] Strict error on static call? Solved!

Just a quick post about Strict standard error when we have a class method which would like to behave differently if called statically.
Apparently, and this is a truly old bogus I opened ages ago, the solution was to supress Strict errors (lol, thanks developers) even if in every other programming language, via overload, this kind of situation could be solved in a bit.

How to solve the problem?

While last post I suggested a couple of runtime solutions, this time I suggest to simply avoid the method definition and use a different one with a meaningful name. In this example I created a String class:

class String {

// choose a recognizable name for protected method
static protected function _concat(array $arguments){
return new self(implode('', $arguments));
}

// use magic __callStatic function
static public function __callStatic($name, array $arguments){
// check the recognizable name
switch($name = '_'.$name){
case '_concat':
// return its call
return self::$name($arguments);
}
}

protected $__value__; // save the string somewhere

// assign initial string, if any
public function __construct($__value__ = ''){
$this->__value__ = $__value__;
}

// use magic __call method
public function __call($name, array $arguments){
// check the recognizable name
switch($name = '_'.$name){
case '_concat':
// normalize expected arguments
array_unshift($arguments, $this->__value__);
// return its call
return self::$name($arguments);
}
}

// this is a String class ...
public function __toString(){
return $this->__value__;
}

}


// test the alchemy
$str = new String('Hello');
var_dump(
String::concat('Hello', ' ', 'World', '!') == $str->concat(' ', 'World', '!')
// true, both are Hello World!
);

As we can see, errors are gone and the code is much easier to maintain. Hope this will help (performances? ... oh, come on!)

[js.php] A JavaScript Object Like PHP Class

PHP 5.3 introduces the Closure class which is really useful and more powerful than good old lambdas via create_function.
These are main limits of Closure class:

  • you cannot serialize a Closure instance (and json_encode does not solve the problem at all)

  • you cannot inject scopes via $this unless the closure comes from a class method


While with an emulated prototype style class, something I tried months ago as well, the first point could not be a problem, to solve the second one is quite inevitable to use a Python like variable as first argument, called $self, to make the Closure both portable and re-adaptable.


JSObject :: JavaScript Object Like PHP Class


/** js.php basic JSObject implementation
* @author Andrea Giammarchi
* @blog WebReflection.blogspot.com
* @license Mit Style License
*/
class JSObject implements ArrayAccess {

// public static prototype
static public $prototype;

// ArrayAccess Interface
public function offsetExists($index){return isSet($this->$index);}
public function offsetGet($index){return $this->$index;}
public function offsetSet($index, $value){$this->$index = $value;}
public function offsetUnset($index){unset($this->$index);}

// Invoked lambdas via $this or self::$prototype
public function __call($index, array $arguments){

// inject $this as first argument
array_unshift($arguments, $this);

// invoke the callback
return call_user_func_array(

// if it has been assigned to the object itself
isset($this->$index) ?

// it has priority
$this->$index :

// otherwise invoke from self::$prototype
self::$prototype->$index
,
$arguments
);
}

// JS like behavior, ready for extends
public function __toString(){
return '[object '.get_class($this).']';
// e.g. [object JSObject]
}

// Relevant Global Object implementations
public function getPrototypeOf(){
return get_class($this);
}
public function hasOwnProperty($index){
return isset($this->$index);
}
public function isPrototypeOf(/* string */ $class){
return $this instanceof $class;
}
public function toSource(){
// we could implement __sleep and __wakeup
// to avoid closure serialization (not possible yet)
return serialize($this);
}
public function toString(){
return $this->__toString();
}


// not standard method, anyway useful
public function toJSONString(){
// we could parse properties in a foreach
// to filter meaningless closures, if any
return json_encode($this);
}
}

// the global prototype is a JSObject too
JSObject::$prototype = new JSObject;

// JSObject factory: e.g. $myobj = JSObject(); // rather than new JSObject;
function JSObject(){
return new JSObject();
}

Above class uses an interface from the great SPL, an in-core extension present since PHP 5.1
The rest is theoretically compatible with old style lambdas, static functions, or new Closure instances. Here we go with some example:

// we can assigns prototypes everywhere ...
JSObject::$prototype->getName = function($self){
return $self->name;
};

$o = JSObject();

// ... even after JSObject instances creation
JSObject::$prototype->writeAge = function($self){
echo $self->getName().' is '.$self->age.' years old.';
};

// assign properties
$o->name = 'Andrea';
$o->age = 30;

// test some JS method
echo $o->toJSONString();
// {"name":"Andrea","age":30}

echo $o;
// [object JSObject]

echo $o->toSource();
// O:8:"JSObject":2:{s:4:"name";s:6:"Andrea";s:3:"age";i:30;}

// or tests runtime methods
$o->writeAge();
// Andrea is 30 years old.

// we can assign a custom method runtime
$o->getSurname = function($self){
return 'Giammarchi';
};

// custom methods have priority over prototype
$o->getName = function($self){
return $self->name.' '.$self->getSurname();
};

$o->writeAge();
// Andrea Giammarchi is 30 years old.

Is it cool? And more is coming for backward compatibility:

// prototype via function name resolution
JSObject::$prototype->getName = 'JSObject_getName';

// the function with a prefix to avoid conflicts
function JSObject_getName($self){
return $self->name;
}

// a simple test case
$o = JSObject();
$o->name = 'Andrea';

echo $o->getName();
// Andrea

And obviously we can do the same with create_function:

// prototype via lambda
JSObject::$prototype->getName = create_function('$self','
return $self->name;
');


Conclusion


Via SPL, closures, and some convenient trick, we could completely change the code style of PHP. Performances are always a priority, in any case, but with a couple of good practices, some discarded or "language useless" piece of ECMAScript, we could use JS style as low level structure for more Object Oriented frameworks or completely different ways to code.

What's next?


It is ages that I am waiting for a stable PHP 5.3 plus PECL extensions (in particular the php_operator to add operator overloads) to be able to create a JavaScript version of PHP. I have already created similar classes and my vision is a one2one JavaScript style framework created entirely via PHP. Craziness? Non-sense? Dunno, just try to imagine a Jaxer like behavior in every host with "just" PHP support ... is it a cool idea? Well, please contact me if you are interested ;)

Monday, March 23, 2009

[IE8] Global constants via defineProperty ... Illusion!

I do not want to spend a single word about Internet Explorer 8 Object.defineProperty implementation, which works only with DOM prototypes and the super global window but not with user defined objects, as __defineGetter__ and __defineSetter__ do since ages:
Standards are an important factor to ensure browser interoperability for the Web developer (n.d. oh, really?!??!?!!!!). The accessor property syntax has only recently begun standardization (you guys have a weird concept of the time ... or the meaning of "recent" in IT therms ...). As such, many browsers support an older, legacy syntax ... (n.d. which at least has dignity to work with every kind of object ... )


Anyway, few things are better than nothing, so welcome to Object.defineProperty!

Let IE8 behaves like every other or change every other to respect new M$ standard?

This was the first question when I thought about this new global function: does it mean we finally have a way to emulate __defineGetter__ and setter in Internet Explorer as well? First of all: NO, since IE implementation works only with DOM and window, secondly, we need to add an Object.prototype method (to be honest ... two) and we all know that Object.prototype is the "untouched one".
So, let's do in the other way, we can add a method to the global function Object, which is less obtrusive and more compatible ^_^;;

if(!Object.defineProperty && Object.prototype.__defineGetter__)
// a silly WebReflection idea
Object.defineProperty = function(obj, prop, getset){
if(getset.get)
obj.__defineGetter__(prop, getset.get);
if(getset.set)
obj.__defineSetter__(prop, getset.set);
};

Well done, now we should simply parse every passed obj to understand if those are IE8 compatible ... is it worthy? ... dunno yet, just for fun, destroy IE8 environment with this evil Object.prototype if you want:

if(!Object.prototype.__defineGetter__ && Object.defineProperty){
// the second silly WebReflection idea!
Object.prototype.__defineGetter__ = function(prop, get){
Object.defineProperty(this, prop, {get:get});
};
Object.prototype.__defineSetter__ = function(prop, set){
Object.defineProperty(this, prop, {set:set});
};
};

Same problem, we cannot use a method with every browser ... the only good part of this global Object method is described in this msdn page, an addEventListener, finally, for IE8 too and every node without usage of wrappers (usually the $ object ...)


The insane idea: Global Constants for EveryBody?

... oooOOOOOOOO Crap! Even if we can do something like this:

// create the evil plan!
Object.defineProperty(
window,
"nobodyCanChangeMe",
{
get:function(){
return "I am like a constant!";
},
set:function(){
throw new Error(
"You cannot change a constant, don't ya know it?"
);
}
}
);

// test the evil plan! (muHaHAHAHA in the background ...)
nobodyCanChangeMe = 123;
// Error: You cannot change a constant, don't ya know it?

You will probably be (un)surprised to know that Internet Explorer 8 (tada, tada, taDAAA!!!) completely ignore the setter whenever you decide to redefine the property!!!

// above perfect evil plan code ... plu ...

Object.defineProperty(window, "nobodyCanChangeMe", {get:function(){
return "you must be joke!";
}});
alert(nobodyCanChangeMe); // you must be joke!


As Summary

VBScript via browser supports constants since dunno how many years. I personally wrote a PHP define like functions ages ago but nothing, Microsoft decided to release IE8 without constants, which are supported almost by evey other (FireFox, Chrome, Safari, Opera -- buggy/meaningless in the latter case) so there is no way to protect our code for JsonP requestes, safe evaluations, whatever you would like to be "99%" sure nobody can change, etc etc ... so this is a thank to IE Team, they worked hard, but this is also a: was it that difficult to put more effort in the JavaScript engine, rather than scam the world with those useless page loading benchmarks?

Enjoy the new Web 2.IE8 Era!

Friday, March 20, 2009

noSWFUpload - Zero Plug-In Multiple Upload

As announced a couple of days ago, I am finally proud to introduce my last library free Multiple Upload Component, now compatible with every browser and always without usage of 3rd parts plug-ins.


This little project has been hosted in Google Code and I promise I'll write there a complete documentation asap. Righ now, you can read the project source code via zip to understand what he little API is doing.

Update I added a couple of sections in the Wiki page ;)

Compatibility?
  • Internet Explorer 5.5 (probably 5 too), 6, 7, and 8
  • FireFox? 3 or greater
  • Google Chrome 1.0
  • Opera 8, 9, and 10
  • Safari 4 (current beta)
  • other browsers via unobtrusive iframe


Try the demo if you do not believe it :P

Monday, March 16, 2009

packed.it ... bye bye my darlin'

I spent a month about two years ago to create packed.it, which has been used by few developers, which cannot compete with other known application even if it is absolutely unique.
Well, the domain is expiring, the site is hosted thanks to a friend of mine, the MyMin project in Python, PHP, C#, JavaScript, will be probably moved in Google Code if and when I will have time.

Right now it is not even working with FireFox, just IE7 and few other browsers ... the reason? No time to update it, and low interests from Web community.

So what's next? I have no idea, but if you are interested, packed.it domain is gonna be free soon, and my service is gonna be down soon as well.

Thanks to those developers who believed in packed.it and used it for some project :)

Sunday, March 15, 2009

Multiple Upload With Progress: Every Browser No Flash !!!

Update: released official version in Google Code, cross browser, and easy to use. blog enry


Ok guys, this is a quick and dirty entry in my blog. I need to write documentation, create the project in Google Code, explain better what I have done and how it works.
I do not want to give you the zip right now because I have to change name (silly me do not check before) and to do last tests ... but basically, what I have created this week end, is a graceful enhanced multiple file upload manager compatible with Chrome, FireFox, Internet Explorer (5.5 or greater), Opera, Safari.



The manager wrap an input type file and manages it allowing multiple files selection, where supported, or one after one insert with possibility to remove one or more file from the list.

Everything is absolutely customizable, since the wrapper is entirely in CSS, the library has a language namespace for errors or messages, and events are created by developers.

In those browsers were Ajax upload is not supported, the progress bar is simulated, but there is the feeling that something is happening.

In FireFox, where Ajax upload is supported, the progress is still simulated but at least the size, sent or total, is real.

Stay tuned for the official announcement, enjoy the demo in my website.

Quick thanks and credit to Silk Icon Set from famfamfam!

P.S. Yes, there is a file type filter as well, Flash like, and I have solved server side $_FILES problem with Safari 4 ... but please wait next blog entry!

Monday, March 9, 2009

Safari 4 Multiple Upload With Progress Bar

Update - I slightly modified the demo page adding another bar, the one for the current file. I'll update the zip asap but all you need is a copy and paste of the JS in the index. Apparently multiple should be set as multiple, rather than true ... in any ... it works as long as it is an attribute.


This one from Ajaxian has been one of the best news I could read about HTML5 specs and browsers evolution.
I could not wait to download Safari 4 and test instantly this feature.
I have always been interested in this possibility, both progress bar, plus multiple uploads and that's why I would like to add this post to this list:


First Step: The Input Type File

We can create a multiple input files in different ways: directly in the layout

<input type="file" multiple="multiple" />

or via JavaScript:

var input = document.createElement("input");
input.setAttribute("type", "file");
input.setAttribute("multiple", "multiple"); // note: input.multiple = "multiple" does not work in Safari 4 beta

I know we all like graceful degradation, but in this post I will only talk about a client side progress bar, something that is cool and possible, so far, only via JavaScript ;-)


Second Step: XMLHttpRequest Version 2

The last implementation of this constructor brings some cool stuff with him, the XMLHttpRequestUpload interface, used by an automatic created property called upload.
The reason this property is as cool as welcome, is that it can trace sent binary data via dispatched events like onload, onprogress, and others.

var xhr = new XMLHttpRequest,
upload = xhr.upload;
upload.onload = function(){
console.log("Data fully sent");
};
xhr.open("post", page, true);
xhr.send(binaryData);

Above snippet is the basis of the new feature introduced by Safari 4, feature better explained in the dedicated example I prepared for this post.


Third Step: The PHP Manager

If we use multiple attribute without XMLHttpRequest, we simply need to set a name, and manage data in the server via the superglobal $_FILES. But if we want to send directly the binary stream, the only thing we need to do in the server, security checks a part, is to save the content sent via input:

<?php
// e.g. url:"page.php?upload=true" as handler property
if(isset($_GET['upload']) && $_GET['upload'] === 'true'){
$headers = getallheaders();
if(
// basic checks
isset(
$headers['Content-Type'],
$headers['Content-Length'],
$headers['X-File-Size'],
$headers['X-File-Name']
) &&
$headers['Content-Type'] === 'multipart/form-data' &&
$headers['Content-Length'] === $headers['X-File-Size']
){
// create the object and assign property
$file = new stdClass;
$file->name = basename($headers['X-File-Name']);
$file->size = $headers['X-File-Size'];
$file->content = file_get_contents("php://input");

// if everything is ok, save the file somewhere
if(file_put_contents('files/'.$file->name, $file->content))
exit('OK');
}

// if there is an error this will be the output instead of "OK"
exit('Error');
}
?>



Last Step: The Client Manager With The Progress Bar

This is the last thing we should care about, and only after we are sure we implemented best security checks to avoid problems for users and the server itself. In this example I did not implement too many checks, so please take it as a hint, rather than a final solution for public production environments.
The client side is really simple and entirely managed via JavaScript.

/** basic Safari 4 multiple upload example
* @author Andrea Giammarchi
* @blog WebReflection [webreflection.blogspot.com]
*/
onload = function(){

function size(bytes){ // simple function to show a friendly size
var i = 0;
while(1023 < bytes){
bytes /= 1024;
++i;
};
return i ? bytes.toFixed(2) + ["", " Kb", " Mb", " Gb", " Tb"][i] : bytes + " bytes";
};

// create elements
var input = document.body.appendChild(document.createElement("input")),
bar = document.body.appendChild(document.createElement("div")).appendChild(document.createElement("span")),
div = document.body.appendChild(document.createElement("div"));

// set input type as file
input.setAttribute("type", "file");

// enable multiple selection (note: it does not work with direct input.multiple = true assignment)
input.setAttribute("multiple", "multiple");

// auto upload on files change
input.addEventListener("change", function(){

// disable the input
input.setAttribute("disabled", "true");

sendMultipleFiles({

// list of files to upload
files:input.files,

// clear the container
onloadstart:function(){
div.innerHTML = "Init upload ... ";
bar.style.width = "0px";
},

// do something during upload ...
onprogress:function(rpe){
div.innerHTML = [
"Uploading: " + this.file.fileName,
"Sent: " + size(rpe.loaded) + " of " + size(rpe.total),
"Total Sent: " + size(this.sent + rpe.loaded) + " of " + size(this.total)
].join("<br />");
bar.style.width = (((this.sent + rpe.loaded) * 200 / this.total) >> 0) + "px";
},

// fired when last file has been uploaded
onload:function(rpe, xhr){
div.innerHTML += ["",
"Server Response: " + xhr.responseText
].join("<br />");
bar.style.width = "200px";

// enable the input again
input.removeAttribute("disabled");
},

// if something is wrong ... (from native instance or because of size)
onerror:function(){
div.innerHTML = "The file " + this.file.fileName + " is too big [" + size(this.file.fileSize) + "]";

// enable the input again
input.removeAttribute("disabled");
}
});
}, false);

bar.parentNode.id = "progress";

};

The external file with sendFile and sendMultipleFile function is in my repository and in the attached zip, while a workable example page with a limit of 1Mb for each file is here in my host.

Sunday, March 1, 2009

PHP to Jaxer Server And Vice-Versa

Basis

If we have a configuration Jaxer + PHP, as is as example in my pampa-j project, we should know that these two languages cannot directly interact as is, for example, with Jaxer and Java.
The interpreted and executed order is this one:

  1. the PHP module parses the request and the page before Jaxer module

  2. after PHP has finished its stuff, the Jaxer Server module parses the page which could has been modified during PHP execution

  3. after the Jaxer Server has finished its stuff, the user receives the generated page

Above order means that we can pass variables to Jaxer but we cannot pass back results to PHP

<?php // simple variable from PHP to Jaxer
$myVar = 'Hello World';
echo '<script runat="server">
myPHPVar = '.json_encode($myVar).';
onload = function(){
// will show Hello World
document.body.innerHTML = myPHPVar;
};
</script>';
?>

As summary, if we print out a script tag wth a valid JavaScript for server, client, or both, Jaxer Server will consider that tag as part of the page to execute.


The Other Way Round?


Since Jaxer Server parses tha page after PHP has finished, and since PHP will not be connecte to the Jaxer Module and will simply close its thread, during Jaxer page generation/parsing we cannot use PHP because there is no connector as is for Java.
At this point we could create a workaround using one of these strategies and considering that all we gonna do will be on the server, before the client will receive the page:

  • create a socket via PHP and connect to it via Jaxer during its page parsing

  • call somehow PHP runtime during Jaxer Execution


While the first point requires skills and the possibility to change server configuration, the second option could be implemented via Synchronous Ajax call from Server to Server.


Sounds Insane, but it is working!

These is a simple test case I created to show you how it is possible to communicate PHP to Jaxer (creating a specific object) and vice-versa, calling PHP functions runtime via Jaxer.
The final concept is showed in next snippet:

<?php
// require the Jaxer.php file to prepare
// the Jaxer.PHP object
// Jaxer is interpreted after PHP
require 'Jaxer.php';
?>
<script runat="server">
// a simple test case, monitor the tme
var t = new Date;
onload = function(){

// retrieve the length of a string
var len = Jaxer.PHP.call("strlen", "test"), // 4
myFuncResult;
try {

// change runtime the page to call
Jaxer.PHP.url = 'myFunc.php';

// call a function defined in that page
myFuncResult = Jaxer.PHP.call("myFunc"); // "Hello Jaxer Server"

// call something undefined to test errors
myFuncResult = Jaxer.PHP.call("noFunc"); // shows an error on the catch
} catch(e) {

// show the error
document.body.appendChild(document.createTextNode(e.message)); // error from PHP, if any
document.body.appendChild(document.createElement("br"));
};

// take the elapsed time
t = (new Date - t) / 1000;

// show some information
document.body.appendChild(document.createTextNode(len + " - " + myFuncResult));
document.body.appendChild(document.createElement("hr"));
document.body.appendChild(document.createTextNode("Executed in " + t + " seconds"));
};
</script>

To make above code possible, all we need are a couple of files, the Jaxer.php interpreter:

<?php
/** Runtime Jaxer to PHP
* (C) Andrea Giammarchi
* Mit Style License
*/

// @string your secret password, it will NOT be showed in the client
$JaxerSecret = sha1('my secret pass');

// if Jaxer Server sent a request with a valid secret and a function to call ...
if(isset($_POST['JaxerSecret'], $_POST['Jaxer']) && $_POST['JaxerSecret'] === $JaxerSecret){

/** Error manager
* @param int error level
* @param string file that generated the error
* @param int line that generated the error
* @param mixed the context (optional, not used)
*/
function JaxerError($level, $message, $file = null, $line = null, $context = null){
echo ":".json_encode(array('level' => $level, 'message' => $message, 'file' => $file, 'line' => $line));
exit(0);
}

/** Exception manager
* @param Exception the generic generated Exception
*/
function JaxerException(Exception $e){
JaxerError($e->getCode(), $e->getMessage(), $e->getFile(), $e->getLine());
}

// error manager configuration
@set_error_handler('JaxerError');
@set_exception_handler('JaxerException');

// Jaxer variable is a serialized object with two properties
// - the name of the function to call
// - one or more arguments to send to use with called function
$js = json_decode($_POST['Jaxer']);

// the Jaxer to PHP result is always a JSON serialized result
echo json_encode(call_user_func_array($js->name, $js->arguments));
} else

// Jaxer needs to know the secret
// and to use the Jaxer.PHP
// this is created runtime via PHP
echo '<script runat="server">'.
str_replace(
'{JaxerSecret}',
$JaxerSecret,
file_get_contents('Jaxer.php.js') // read the file
).
'</script>';
?>

the Jaxer.php.js file with the JavaScript runtime created object:

/** Runtime Jaxer to PHP
* (C) Andrea Giammarchi
* Mit Style License
*/
Jaxer.PHP = {

// the url with Jaxer.php file
url:"Jaxer.php",

// the PHP.call function
// Accepts the name of the PHP function to call
// plus zero, one, or more arguments to send
call:function(slice){
var send = {
async:false,
method:"POST",
onsuccess:function(response){
if(response.charAt(0)===":"){
var result = JSON.parse(response.substring(1)),
e = new Error;
for(var key in result)
e[key] = result[key];
send.result = null;
throw e;
} else
send.result = JSON.parse(response);
}
};
return function(name){
send.url = Jaxer.PHP.url;
Jaxer.XHR.send(
// {JaxerSecret} is replaced via PHP
"JaxerSecret={JaxerSecret}&Jaxer=" + encodeURIComponent(
JSON.stringify({name:name, arguments:slice.call(arguments, 1)}
)), send);
return send.result;
}
}(Array.prototype.slice)
}

... and finally, a generic page with one or more functions defined, in this case the myFunc.php file:

<?php
// require the Jaxer to PHP manager
// if this page is called directly
// the secret will NOT be whoed
// while if this page is called
// via Jaxer.PHP, the manager
// will simply execute the required code
require 'Jaxer.php';
function myFunc(){
return 'Hello Jaxer Server';
}
?>

The secret is a truly simple security system to avoid direct php page calls and since it is interpreted only on the server, the client will never know this secret (unless our server is not exposing source codes, in this case the secret should be already hashed via sha1 in the source).


Pros And Cons

This strategy could sound cool but it is not the ideal way to interact between these two different modules. The Jaxer to Java way is much better but at least here we have the possibility to send back something or to do via PHP something impossible to do via Jaxer. The fact I put a timer to monitor the delay means you should pay attention because this way is extremely slow. The ideal case scenario is, when absolutely necessary, call PHP only once, creating a clever function able to receive one or more arguments, delegates tasks in the current PHP code, and send back a single object with one or more results. In few words, if you are able to perform one single call to send and receive everything you need, this solution could be fine. In every other case, this solution could require an insane stress for the server and for a single page to show.

In any case, have fun :)

P.S. Here I am with a zip file to test directly this post code