Flash to support H.264
Jed Wood pointed me to an article from one of the engineers of the flash player, stating Flash is going to start supporting H.264 video (in essence, mpeg4). So yes, this means you can play MOVs in flash, if they are using H.264 and the AAC audio codec.
The signs were already there, as ON2 announced H.264 support in their flix product line, but now it's official.
This pretty much means the death of the proprietary FLV format, which was both from a business and a technical standpoint inferior. Before flash supported a subset of H.263 (a.k.a. Sorenson Spark) and VP6. Although converters for H.263 have been available for a long time, the actual FLV format (wrapper) and the much better VP6 codec remained 'officially' inaccessible. MPEG4 is still a patented technology, but at least there is now a wide range of choices and software to produce this.
The new flash media server, which can be used for video (up and down)streaming will also start supporting this. It's not clear to me if the proprietary Nellymoser codec, which is used for recording audio from the flashplayer will also be replaced.
I wonder what this means for ON2, who just lost their single key selling point for their Flix software. They never had transparent pricing for their (buggy) Flix engine, so now they will lose the fact that they were the only way to go if you wanted to convert video using a modern codec.
PHP: Arrays vs. Objects
In a lot of cases arrays are used in PHP to store object-like information, like the results of a database query. I do this a lot too, but I kind of want to change things around to make use of VO's. I feel this makes a lot more sense, since most of the application I build are heavy OOP anyway, and I get all the added OOP benefits, like type-hinting, inheritance.. well, you know the deal.
I wanted to see what the differences would be in terms of memory consumption, so I set up the following test:
<?php
// first test simple associative arrays
$memory1 = xdebug_memory_usage( );
$data = array();
for($i=0;$i<1000;$i++) {
$data[] = array(
'property1' => md5(microtime()),
'property2' => md5(microtime()),
'property3' => md5(microtime()),
);
}
$array = xdebug_memory_usage()-$memory1 . "\n";
// Now do the same thing, but with a class..
class Test {
public $property1;
public $property2;
public $property3;
}
$data = array();
$memory1 = xdebug_memory_usage( );
for($i=0;$i<1000;$i++) {
$test = new Test();
$test->property1 = md5(microtime());
$test->property2 = md5(microtime());
$test->property3 = md5(microtime());
$data[] = $test;
}
$object = xdebug_memory_usage()-$memory1;
echo 'Arrays: ' . $array . "\n";
echo 'Objects: ' . $object;
?>
My results were
Arrays: 536596
Objects: 521932
I knew there was a good chance objects would take up less memory, because arrays need to store both the propertyname (or key) and value for every record, while the object only needs to store the values, because the propertynames are stored centrally in the class definition, what I didn't expect was that using arrays takes more than 20 times more memory. This is hardly an accurate formula, but it does tell you something.
Right, that was stupid.. I had my testing code wrong and I did the $data=array(); right after the second xdebug_memory_usage(). The actual conclusion here is that there's not much difference. I was hoping the objects would make a significant difference, but its minimal.
PHP and circular dependencies
Today I noticed the strangest bug in PHP. Apparently there's a problem with circular dependencies and interfaces.
This is how the problem occurs:
<?php
// this is class1.php
require_once 'iclass.php';
class class1 implements iclass {
}
?>
<?php
// this is class2.php
require_once 'class1.php';
class class2 extends class1 {
}
?>
<?php
// this is iclass.php
require_once 'class2.php';
interface iclass {
function setSomething(class2 $object);
}
?>
Now, if you run class1.php, you will get the following error:
Fatal error: Class 'class1' not found in /home/filemobile/testscript/class2.php on line 5
I know this is not proper OOP, but its still a strange error. Normally PHP is pretty good at these weird structures ;). Weirdest thing was that it happened for me on one server, but not the other.
There is a bug marked bogus for this, which is understandable. It would be great though if the PHP could somehow throw an error thats a bit more helpful =P. Its a strange error, especially since I could only reproduce it with this structure, and not with for example just 2 classes with circular dependencies.
Future of SabreAMF
I've been asked a bunch of times what's gonna happen with SabreAMF.
The thing is, the goals of SabreAMF were a lean AMF-parsing library without any pre-cooked frameworks like AMFPHP or WebOrb. What I mean with that is that both of those products force you to structure your service classes in a specific way, whereas I needed to fit an Flash Remoting library in existing business logic for webservice.
I feel like I have succeeded in that goal. It has became what I wanted it to be, it's in use at a few high-traffic sites and no bug reports have came in in the last 4 months.
So what's next?
The next step is to put the version number on 1.0 and freeze the codebase, unless new bug reports come in. In the meanwhile I have been working on a more complete web service framework, that will make use of SabreAMF, and will actually looks more like AMFPHP's approach. I have to work out copyright issues before I can promise it will get open sourced, but I have a good feeling about it.
Features/Ideas:
- Service-classes are specified using an xml file.
- Services are accessible using AMF, JSON, XML-RPC, SOAP, REST and PHP-RPC.
- VO-Classmapping configuration for Actionscript 2, Actionscript 3, SOAP and PHP-RPC.
- Automatic self-documentation using Reflection and PHP docblocks.
- Proxy-service classes, allowing you to proxy external webservices. (this allows you to access SOAP services using PHP-RPC, XML-RPC services using AMF, etc.)
If anyone thinks this is not a bad idea, and willing to contribute drop me a line, or post a comment.
PHPRPC and PHP frameworks
I started the process to submit PHPRPC to the major frameworks. I feel like I should submit it to all the major frameworks, so I can make sure people can use PHP-RPC regardless of their framework of choice.
Besides that, it might be a good way to gather feedback or critique from the pro's.
PEAR
For PEAR I submitted it as a new PEAR2 package. PEAR2 is the upcoming next major version of PEAR, and will be PHP5-only. Much of my code (seemed) to follow PEAR2 coding standards, but the approval process will tell.
The most interesting (or weird) change I had to make the standards to include classes from within other classes. The old PEAR standards dictate:
<?php
require_once 'My/Other/Class.php';
?>
Which assumes PEAR and its packages are in the include_path. However, the standard for PEAR2 is:
<?php
if (!class_exists( 'My_Other_Class',true )) {
throw new Exception('Undefined class: My_Other_Class');
}
?>
So, this means that the user of the package has to manually include all the dependencies. There is also an allfiles.php in every directory, which loads the entire package.
This allfiles.php is considered 'for beginners'. The wiki states that its also for opcode cache friendliness, but this is false (I submitted a bug report). So as a consequence of this all that using PEAR2 packages becomes a bit more harder to use for the following target audience: "Advanced developer, but doesn't want to trace each class' dependency tree"
Solar Framework
I opened a ticket in Solar's trac asking if its smarter to first write the Solar implementation, or first ask for approval for the contribution, because it would be good to know if Paul M. Jones hates the idea before I start.
Solar follows PEAR's old coding standards. The only annoyance here is that I need to prepend underscores to every private and protected property. (An idea that stems from the PHP4 era, where there was no property visibility).
Zend Framework
I haven't really started with Zend yet, the coding standards seem to be nearly the exact same as the ones I use myself (except for the change from Sabre_ to Zend_), but in order to submit code to Zend, or even propose a package you have to sign a contract first; which means I have to print, sign and scan their pdf. Sadly, the only type of paper we have in this house is rolling paper.
PHP-RPC update 4
This should be the last version of the spec for PHP-RPC, unless somebody has some great feedback with stuff I overlooked. It might need some clarification and better writing here and there, but I think the general idea is there.
The api for the server class currently works the exact same as before, but support for multi-calls has been added. I also added a client class, which is helpful when you surpass the prototyping phase and you need a more decent way to interact with the service.
Example usage:
<?php
$url = 'http://localhost/~evert/phprpc/server.php';
require_once 'Sabre/PHPRPC/Client.php';
$client = new Sabre_PHPRPC_Client($url,'system');
$data = $client->testingMethod('test');
print_r($data);
?>
Multi-call example:
<?php
$url = 'http://localhost/~evert/phprpc/server.php';
require_once 'Sabre/PHPRPC/Client.php';
$client = new Sabre_PHPRPC_Client($url,'system');
$client->startMultiCall();
$client->testingMethod('test');
$client->testingMethod2('test');
$data = $client->execMultiCall();
print_r($data);
?>
The source can be downloaded from here. I also added the code to a subversion repository.
Here's the updated proposal. Changes have been highlighted.
The proposal (0.3)
Goals
- Client should be very easy to implement. Server is allowed to be a bit more complex.
- No duplication of the HTTP protocol. For example, HTTP already provides encryption, redirecting and authentication.
- PHP 4 and 5 compatibility. (and 6 when it is released).
- Client and server implementations should be built from the idea 'be strict in what you produce, be liberal in what you accept'
The request
Requests are made using either GET or POST. Both should be accepted. GET is more appropriate for fetching information, whereas POST is used for posting new data. POST has the advantage that it doesn't have any limits in the size of the request and an encoding can be supplied. GET has the advantage that information can be fetched using a one-liner.
When there is no encoding specified, UTF-8 is assumed. Data supplied using POST should be encoded as application/x-www-form-urlencoded (this is how a browser submits data by default).
The method thats called should always be supplied as the 'method' variable. The method can contain periods (.) to separate namespaces like XML-RPC. Arguments can be specified in two ways, and the API documentation should specify what the appropriate way is. The first way is using named arguments, a GET example would be:
http://www.example.org/services/phprpc?method=getUsers&maxItems=20
The method here is getUsers, the named argument is maxItems and its value is 20.
The second way is using a list of arguments, which might be more appropriate in some cases where you want to directly map services and methods from a class on the server to the api. This is also how XML-RPC works.
http://www.example.org/services/phprpc?method=getUsers&arguments[0]=20&arguments[1]=1
The first argument is 20, the second is 1.
Smart servers should use reflection to automatically map named arguments to the actual arguments in a list.
Clients SHOULD supply the version of PHP they are running. This can be either a complete version number, or just the major version (e.g.: 4, 5, 6). Clients should supply this as the phpVersion parameter. If the versionnumber is not supplied, the current stable PHP version is assumed, which is at the time of writing 5.
Clients MAY also supply the version of the PHP-RPC protocol as the 'version' parameter. Currently this is 0.3.
Clients MAY supply a returnClasses parameter. The value for returnClasses is either 0 or 1 and this can tell the server if the client is aware of typed objects that might be sent from the server.
The server
The server MUST allow requests both GET and POST requests. The server MUST treat any incoming text without encoding as UTF-8.
The server SHOULD allow both named arguments and indexed arguments for methods where this is possible.
If the client sent phpVersion the server MUST convert the returned serialized string so it can be read by the server. If the phpVersion is 4 or 5 the server MUST convert all unicode-strings (type U) to binary strings (type s). If the phpVersion is 4 the server MUST convert all private and protected properties to public properties.
Servers SHOULD also convert all typed objects to either STDClass'es or arrays when the client supplied returnClasses is set to 0, if this is appropriate.
The return data is always in PHP's serialize data format. The Content-Type header should always be 'application/x-php-serialized'
The server will always return an error with the following properties:
- result
- The actual return data.. (or an array with information about an exception, in which case it should have at least the 'message' property.)
- status
- HTTP status code for the method call. (200 = success, 500 = internal server error, 400 = bad request, etc etc.) Custom error codes have to start at 600.
- version
- optional: PHP-RPC protocol version. Currently this is 0.3
- server
- optional: Name of the server. Can be any string.
Multicall
Servers should be able to parse multi-call requests. This allows a client to wrap multiple methodcalls into one http-request. Multi-call only works with arguments specified as sequences.
Making a multicall is simple, instead of supplying the method as a string, it should be specified as an array with 1 or more methodnames. Arguments are also wrapped in an array (which then contains multiple arrays per method.)
The 'result' key in the response structure will also have to be an array. Each item in this array contains a at least a 'status' and a 'result' property, which have the same meaning as in the main result structure.
This means the status of the entire call can be 200 (success), while the individual responses to methods can contain an error code. The top-level status code will only be an error if the actual request was somehow malformed, and the server couldn't process the individual requests.







