Use PHP functions in JavaScript

php.js

php.js Logo php.js is an open source project that brings high-level PHP functions to low-level JavaScript platforms such as web browsers, browser extensions ( Mozilla/Firefox, Chrome ), AIR, and SSJS engines like V8 ( node.js, v8cgi ), Rhino, and SpiderMonkey ( CouchDB )

If you want to perform high-level operations on these platforms, you probably need to write JS that combines its lower-level functions and build it up until you have something useful like: strip_tags(), strtotime(), number_format(), wordwrap().

That's what we are doing for you.

Pure JavaScript so no additional components required.
To use php.js you can either:

PHP is a language with many high-level functions and while they're not always implemented as consistently as we'd like (mostly to blame on its underlying C parts), it has a huge following familiar with its syntax so it makes sense to pick its API as a reference. Eliminating the need for our own documentation, thus making life easier, we hope.

We recognize JS - on the other hand - has beautiful language features, and we encourage you to learn them. Never let php.js be an excuse not to.
For the same reason, we're not porting entire language or control structures of PHP; we stick with the functions.

That said, we think of it as a challenge to port everything and decided to also port low-level PHP functions like strpos even though it may have a JavaScript counterpart (String.indexOf).
Cause besides the intellectual challenge for us, porting more also opens up php.js to all kinds of thought excercises and study purposes.
And so we leave it up to the developer to decide what to take from this resource.
And what not.

Featured Functions

date()
Date-formatting, just like you know it from PHP

base64_decode()
Safe & easy data transport, decode messages in JavaScript that were encoded by PHP.

The History of php.js

Kevin van Zonneveld was once working as developer on a project with a lot of client (JS) / server (PHP) interaction, and found himself coding PHP functions (like base64_decode & urldecode) in JavaScript to smoothen data transport between the two languages.

He stored the stored the functions in a file called php.js which was included in the project. But even when the project was done, it remained fun trying to port PHP functions to JavaScript, and so the library grew.
There was a technological challenge in trying to recreate functions such as date, or sprintf.

Eventually Kevin decided to share the little library on his blog, triggering the enthusiasm of a lot of developers worldwide. The project was open sourced in 2008, and many people contributed their own functions in the comments sections of Kevin's blog.

To try and maintain quality, examples from original PHP documentation were taken and added as unit tests in the header of each function. These are the same bits of code you can see under the Example section for any function.
As bugs are reported, more test cases are added to avoid regression.

It was decided that the library deserved a bigger home and a face of its own, and so the php.js core team (which at that time consisted of Michael White, Felix Geisendörfer, Philip Peterson and Kevin) developed the phpjs.org website.

Different core members have come & gone but there has always been a select group pushing the project forward.

Late 2008 Brett Zamir started contributing and did't stop. In April 2009 he was responsible for over 245 different PHP functions and has had many ideas considering php.js' future.

Because the library became too big to include at once, and having users copy-paste functions to their projects proved tedious, Kevin started working on a compiler that allows programmers to select ONLY the functions they need, and wrap them up in a single customized php.js file.
This took away overhead and even allowed for easy upgrading.

In September 2009 we moved the development of the project to GitHub.
This opened up a lot of features to help colaboration in development.

Gaining popularity in the SSJS world mostly due to node.js people needing functions such as html_entity_decode, we received a lot of requests for a CommonJS compatible library and in April 2010 the compiler took it's first steps to support it.

And that's where we are now.

We are still trying to port and perfect functions.
Want to help out & become a part of our history? Why not add a comment with new or better code?
It is that easy.

Comments

Add Comment
Use:
[CODE]
your_stuff('here');
[/CODE]
for proper code formatting
By submitting code here you are allowing us to use it in php.js hence dual licensing it under the MIT and GPL licenses

Gravatar
Joakim
Aug 13th Permalink

q  You guys... Are
F-U-C-K-I-N-G F-A-N-T-A-S-T-I-C!

Thank you VERY much!

Gravatar
Zhu Hquan
Aug 9th Permalink

q  ha good

Gravatar
jack egware
Aug 9th Permalink

q  thorn 211

Gravatar
jack egware
Aug 8th Permalink

q  keys of today i nagra2 and 3 keys

Gravatar
jack egware
Aug 8th Permalink

q  i need the keys for thorn 2/3 digi tv

Gravatar
hi
Aug 3rd Permalink

q  <SCRIPT>

function sumDigits(num) {
var i, sum = 0; //
can declare two variables at once

for (i = 1; i <= num; i++) {
sum += i; //
add each number to sum (ie, 1 + 2 + ...+
num)
}

// Display result
alert("The sum of the digits from 1
to "+ num + " is:\n\n\t " + sum);
}

</SCRIPT>

Gravatar
hi
Aug 3rd Permalink

q  

your_stuff('here');


Gravatar
adasdsad
Aug 2nd Permalink

q  

your_stuff('here');

Gravatar
bhupal
Jul 17th Permalink

q  thanks :)
i will no more miss the date() & print_r().
keep up the good work!

Gravatar
jiduw
Jul 14th Permalink

q  Good.Thanks

Gravatar
Claudio de Taunay
Jul 11th Permalink

q  Congratulation ! Great work. Keep walking men ...

Gravatar
David
Mar 4th Permalink

q  Hello,

Your website is nice but it's a nightmare to access with an IE.

I think there's a solution according to:

http://aralbalkan.com/912

Thanks for your good functions.

Gravatar
Kevin van Zonneveld
Mar 1st Permalink

q  @ Dino B.: Placing it on a CDN would encourage the use of the default package in production. While in fact we are trying to stimulate people to use only the functions they need. Either by compiling, or just copy-pasting some of our functions.
Please never hotlink GitHub's raw sources. As you can achieve the same thing (only without using up their bandwidth) by doing:

$ cd /my/web/app/webroot/js/
$ git clone git://github.com/kvz/phpjs.git

from now, to update phpjs, you can do a:

$ cd /my/web/app/webroot/js/phpjs; git pull;

and to use functions you can include:

/js/phpjs/functions/array/is_array.js
/js/phpjs/functions/datetime/strtotime.js

in your webpages.




Gravatar
Dino B.
Feb 23rd Permalink

q  Is there a consideration to place this library on a CDN somewhere? Secondly, is hotlinking to the functions (their github locations) encouraged, prohibited, or a gray area?

Gravatar
Brett Zamir
Feb 20th Permalink

q  I added the test files (converted to JavaScript) at http://github.com/kvz/phpjs/tree/master/_workbench/tokenizer/tokenizer_tests/ . Some of them need php.js functions added and there may be some imperfections in the PHP-to-JS conversion process (I corrected some of them that Harmony Framework missed, though it seemed to do a pretty good job). We'll also need to consider the best way to parse the test files, run the JavaScript, and test against the expected results...

Gravatar
Brett Zamir
Feb 20th Permalink

q  @Marco: I'm sorry if I get carried away sometimes; sorry for too much information; I forget who I've talked to about these things. And don't be afraid to ask questions for anything.

Yes, I went back to your constant values; that's good we use the latest.

I agree finishing token_get_all() and testing it is a good idea; I just started the php-to-js code for fun and to test the concept a little.

As far as testing, that is exactly what we can use the "phpt" files are for. They are test files in the PHP source code. They are written in PHP (though with some blocks indicating what is being tested, what the result is expected to be, etc.) and my idea was to use a PHP-to-JavaScript converter so we could use those tests against all of our functions. These tests for token_get_all can be found in the PHP source code at /ext/tokenizer/tests/ . Again, until we have our own converter, we can try http://www.harmony-framework.com/ for converting those "phpt" files into JavaScript.

Gravatar
Marco Marchiò
Feb 20th Permalink

q  @Brett: You must clarify me something, remember that i'm new to this project, i've no experience in community work (and related tools such as Github), i'm italian and i speak a medium-level english and right now i'm tired so be patient:).

You talk about ".phpt" files where can i find them and what do you mean by adapting them to Javascript form?

For the Php parser i think we should finish to fix the token_get_all with lots of tests, improve its performance, create some guidelines about the implementation of the parser and then build it on the token extension.

Gravatar
Marco Marchiò
Feb 20th Permalink

q  @Brett: You are doing a very good work.

I get the constants value from PHP 5.3 so i think that when the function will be released you must change their value according to the last version of PHP.

For the \r\n problem i agree with you to make the \r optional, i forgot that it's present only on Windows.

Right now i'm very busy at work, but when i'll finish (i hope soon) i'll be glad to help you with everything.

Gravatar
Brett Zamir
Feb 19th Permalink

q  @Marco: As I think I may have mentioned before, I have modified your functions to follow our coding standards and also support IE since you cannot do str[3] in IE--string characters can only be accessed by str.charAt(3). (Annoying, but true.)

I believe I also fixed a problem with one of your variables not being declared and thus global.

I also added a HEREDOC test. There was some work to be done with HEREDOC handling but that is now fixed, so again, please apply my changes first before you work on the code again: http://github.com/kvz/phpjs/tree/master/_workbench/tokenizer .

I also renamed token.js to token_get_all.js and renamed what I think used to be "test.min.js" to a more descriptive "file_get_contents.min.js".

As far as \r\n, shouldn't such checks be \r?\n since \r is only Windows? I made the \r optional.

Also, I needed to temporarily add different values for the constants to compare on my system (5.2.6) which uses different numeric values for the constants... What version of PHP are you using? 5.3 or 6? I've kept my own values in the comments but just now reverted to your values since it appears you are using a later edition of PHP.

I also added some additional test files, and supplemented your test with var_export(), but I really think we need to have a greater interaction between PHP and JS to summarize in a line exactly what differed between the PHP version and the JS version (with maybe the PHP producing the value which JS checks against its own).

I'd also really like to adapt all of the ".phpt" test files in the PHP source to make sure token_get_all.js is parsing PHP perfectly. I think this is a very important function you've made, so I hope we can prove to ourselves and others that this is really robust.

Also, I added a feature to token_get_all.js so that if the user has "this.php_js.phpParser" defined (though maybe I should make it settable via this.php_js.ini so that people can use ini_set() instead), that object's methods will be called with arguments indicating information about each segment currently being parsed (they'll also need token_name.js in such a case; see http://github.com/kvz/phpjs/tree/master/_experimental/tokenizer ). Although someone can do this with the return results of token_get_all(), it will be faster (and live) to work during the original parsing. And I only need to add a couple of lines of code to get this functionality.

See PHPTokenizer.js for a skeleton object that can be used as the "this.php_js.phpParser" and see PHPToJS.js for an early beginning at a PHP-to-JavaScript translator which can also be used as an example of such a parser object. We might also get some ideas if not code from the Harmony Framework (at http://www.harmony-framework.com/ ) about how to finish making such a translator.

I am a little busy to work on this now, but would you be interested in adapting the ".phpt" files into JavaScript form to make sure all of the tests are working? It'd be great to be able to run the tests, and if not showing a diff, at least just summarizing which line is failing and how many lines in the test are failing. Normally for other functions, I think it'd already be ready for release, but I think this one is of the nature that it really should be fully systematically tested first. Then, we can maybe use it to convert other ".phpt" files into JavaScript! :) Or we could just use Harmony Framework for now, though phpt files also have some non-JS blocks we'd need to parse as well...

Anyhow, some really incredible work, thank you again!!!

Gravatar
Marco Marchiò
Feb 15th Permalink

q  @Brett: Ok let me know if you find some bug

Gravatar
Brett Zamir
Feb 15th Permalink

q  @Marco, I did receive your original email, so no need to send it again. Again, please see http://github.com/kvz/phpjs/raw/master/_workbench/tokenizer/ as I have made modifications of your code there to follow our standards. I'd appreciate it if you could use those versions if you make any further changes. This seems like some extremely impressive work, but I'd like to study it more carefully and maybe compare it to the EBNF out there, etc.

Gravatar
Marco Marchiò
Feb 15th Permalink

q  @Brett: i did not receive your email, if you want to try again i will send you back the test suite that i've builded. Anyway to create this function i haven't looked at any source, i've tested it with a lot of scripts untill i've solved every bug. I've tested the result of the original php function, on a 200kb script, with the one returned by the js function and the result was exactly the same. The only functionality that i haven't tested is the HEREDOC.

Gravatar
Marco Marchiò
Feb 15th Permalink

q  @Brett: i did not receive your email, if you want to try again i will send you back the test suite that i've builded. Anyway to create this function i haven't looked at any source, i've tested it with a lot of scripts untill i've solved every bug. I've tested the result of the original php function (on a 200kb script) with the one returned by the js function and the result was exactly the same. The only functionality that i haven't tested is the HEREDOC.

Gravatar
Brett Zamir
Feb 15th Permalink

q  @Marco: Actually, please see http://github.com/kvz/phpjs/raw/master/_workbench/tokenizer/token_get_all.js for the latest of your function instead

Gravatar
Brett Zamir
Feb 15th Permalink

q  @Marco: I sent you an email in reply a few days ago. I haven't gotten any reply to it.

FYI, just now I made more changes to bring your token.js (now changed to token_get_all.js and available at http://github.com/kvz/phpjs/raw/fdecb6087c5843e498a63b4e96ae5b6c063e2624/_workbench/tokenizer/token_get_all.js ) more up to our coding standards (see http://wiki.github.com/kvz/phpjs/developerguidelines ) and I also caught a few bugs, now fixed. But I still haven't taken a good look at the code.

Out of curiosity, how did you write this code? Did you look at the C source, use someone's EBNF, or what?

Please see lines 513, 642, 691 for whether those are accidental assignments or not. As maybe the most important coding standard, please don't do inline assignments, as it is unclear whether it is deliberate or not; assign the variable in a separate line.

Gravatar
Marco Marchiò
Feb 15th Permalink

q  @Brett: Have you received my email?

Gravatar
Brett Zamir
Feb 13th Permalink

q  @LEx: Yes, that is a possibility, but there are a couple of reasons we don't take that approach:

1) Adding methods to the built-in object's prototypes can conflict with other libraries or code, adding a kind of omni-global. The problems can occur if other libraries try to add functions of the same name to the prototype, or, more insidiously, cause problems for those iterating over such object (or array, etc.) properties. Yes, when iterating over object properties, the user should always filter out functions or ignore properties which are on the prototype, but many people (and libraries--including many of the functions still in our library) do not do this filtering, either because they don't know about the need for it, or because they don't want to use libraries that intrude in this way. See http://www.jslint.com/lint.html#forin or http://javascript.crockford.com/code.html#for%20statement

2) We also want to make at least one version familiar and easy to PHP developers, though that doesn't prevent us from making other versions like the namespaced version, but it could add some difficulty to maintenance.

One way around this might be to use our own wrappers for things like arrays.

For example, we might change our function array() (different from the built-in JavaScript Array() object) so that when someone does:

var a = array();



they can also use:

a.in_array(...)



Implementing object-style versions that didn't add to the built-in prototypes might work, even though they would require things like strings to also have wrappers created for them, thus not being as convenient, and, even with this, there is still the problem of iterating properties.

And we could have a version for users who didn't care about problems from adding to the native object's prototypes.

Either of these would definitely change the regular PHP API as the input argument would be removed, but other users could still use the regular version if they wished.

One other potential advantage of the wrapper approach would be that other chaining methods could exist, for example, functions that don't return arrays could be combined with those that do into a long chain:

arr.returnArrays().shift(...).map(...).push(...);



As I recall Kevin isn't interested in making such a version part of the regular compiler, but we could host alternative versions if someone is interested in maintaining them or writing code to automate conversions on the server side.

Gravatar
LEx
Feb 12th Permalink

q  Why you dont use prototype to inherit and expand native Javascript object like Array, Date or String. It wouldnt be better to use [1,2,3].in_array(1) rather than in_array(1,[1,2,3])? Javascritp is prototype based language. In other hand it can downgrade performance... but still why dont use this approach?

Gravatar
Brett Zamir
Jan 31st Permalink

q  @Marco: Sorry for the delayed reply... Have you seen http://www.php.net/manual/en/tokens.php and also the comments there? There's some reference to whitespace as a tokens...

Gravatar
Marco Marchiò
Jan 28th Permalink

q  Hi, i'm trying to create the token_get_all function and i need help on a little problem.
Do you know when whitespaces (\t,\n,\r and spaces) are considrered tokens?
The orignal PHP function get only some of them but i can't understand which ones.

Gravatar
Brett Zamir
Jan 27th Permalink

q  @cynosure: Hi! Don't mean to be unfriendly, but I imagine Kevin would prefer we limit discussion here to php.js functions. But really quickly, it appears that IE may be (mistakenly) considering the XML Declaration at the beginning of the document as though it were a node (probably considering it a processing instruction which it is not, even though it looks like one)--the declaration info should only be available to the DOM as document.xmlVersion, document.xmlEncoding and document.xmlStandalone , though browser support is unfortunately limited even in Firefox; see http://brettz9.blogspot.com/2009/04/xml-dom-support-test.html ). Thankfully, you can still make cross-browser code here in testing whether the nodeName of a "processing instruction" is "xml"; since processing instructions cannot be "xml", you would know it is the bogus IE one and can be avoided.

You could confirm IE indeed treats it this way by printing out the nodeType as well; see https://developer.mozilla.org/en/nodeType for the codes. Also, your example is not recursive, as if it were, you would also need to check whether the node were an element and then recurse on its children; currently you are only iterating through the top level nodes. Maybe this was a simplified example...

Gravatar
cynosure
Jan 27th Permalink

q  Hi!

I'm working now on an xml parser (not yet on a php type XML API object), but I fount a new funny difference between IE6-8 and any other browsers.

I have a simple XML:


6



When I try to loop the elements in a recursive way, the code above works different in these browsers:


xml2Array = function(xml)
{
var nodecount = xml.childNodes.length;
if(nodecount > 0)
{
var log = '';
var arr = new Array();
for(var i=0;i {
log = log + i + ' -> ' + xml.childNodes[i].nodeName + '
';
}
document.getElementById('foo').innerHTML = log;
}
else
{
var arr = false;
}
return arr;
}



In IE writes out:
0 -> xml
1 -> main

In other browsers:
0 -> main

Gravatar
Brett Zamir
30 Dec '09 Permalink

q  Interesting about the delete operator. I knew it didn't work with variables, and imagined it wouldn't work on some built-in objects, but nice to know that formally.

Nice set of examples. It's supposed to get even weirder in IE as far as ordering if you use an object and with properties inherited from the prototype. It's sad that what may be the most usable scripting if not programming language in the world is the least updated. I can live with most of JavaScript's other quirks, even the ease of making accidental globals, but this one should plain and simply just be fixed in the spec and reality.

Gravatar
Brett Zamir
30 Dec '09 Permalink

q  Interesting about the delete operator. I knew it didn't work with variables, and imagined it wouldn't work on some built-in objects, but nice to know that formally.

Nice set of examples. It's supposed to get even weirder in IE as far as ordering if you use an object and with properties inherited from the prototype. It's sad that what may be the most usable scripting if not programming language in the world is the least updated. I can live with most of JavaScript's other quirks, even the ease of making accidental globals, but this one should plain and simply just be fixed in the spec and reality.

Gravatar
cynosure
29 Dec '09 Permalink

q  @Brett Zamir: The delete method have an other issue, it can't remove an element if it have a DontDelete attribute.

https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Operators/Special_Operators/delete_Operator

In the other hand, associative arrays works in IE6 too, but this is not really an array, this is an object, so .splice won't work in any browsers:

var foobar = new Array();
foobar['x'] = 'a';
foobar['y'] = 'b';
alert(foobar['x'] + ' ' + foobar['y']); // writes "a b"
// and the problems:
alert(foobar.splice('x',1)); // does nothing, writes empty window
alert(foobar.splice(0,1)); // does nothing too
alert(foobar['x'] + ' ' + foobar['y']); // writes "a b" again
// with delete:
delete foobar['x'];
alert(foobar['x'] + ' ' + foobar['y']); // writes "undefined b"
for(var key in foobar) { alert(key); } // writes "y"
// let's test the element orders
foobar['x'] = 'c';
alert(foobar['x'] + ' ' + foobar['y']); // writes "c b", its ok
for(var key in foobar) { alert(key); } // writes "x" and "y" in IE6-8, "y" and "x" in all other browsers



I know, this is exactly what you wrote, I only made a test to everyone who wants to know how it works.

Gravatar
Brett Zamir
29 Dec '09 Permalink

q  @cynosure: Looks like someone else here tried something similar: http://phpjs.org/functions/array_pop:329#comment_354 .

As far as a reference to an array, whatever value you pass in to a function, if it is an array or object, its elements can be acted on by reference and in fact only by reference unless you manually make a copy (though you cannot replace the whole object with something else, or that does make a copy). So, we could adapt your function to work by reference (though still breaking the PHP API which only uses one argument):

function unset(array,index) {
    if (typeof array === 'object' && typeof array.length == 'number') {
        array.splice(index, 1); // Using the delete operator will replace the old value
        // with "undefined" in its old slot, but we also want to remove the slot itself,
        // so with arrays (in IE too), we can safely use splice().
    }
    else { // Objects
        delete array[index]; // For object properties, this works pretty well, except potentially in IE where
        // the property will thankfully no longer be iterated, but it has the annoying feature (for
        // the sake of our using objects to imitate PHP associative arrays) that if you later try to
        // add back a value with the same property name, it will put your new value in the old
        // iteration position.  So IE does not truly delete the property, though it may appear that way.
        // All other popular browser implementation seem to truly delete the property (and iterate
        // in order), at least if it is not an inherited property, but the latest ES spec wasn't able
        // to persuade IE to change this behavior
    }
}



See the 2nd comment above for the potential problems with this though. Basically in IE, simple objects as associative arrays just won't work perfectly. It is very disappointing. You can get around this by creating an object which wraps your data, but that can get quite ugly. Otherwise, you just have to keep your keys in one array and values in another array.

This is not to speak of our other challenge here of trying to work with only one argument in unset(). JavaScript does not allow us to get the container object or array if we only know the property. Our experimental version of unset() (at http://github.com/kvz/phpjs/blob/master/_experimental/var/unset.js ), allows us to pass in a single argument, but it is a (necessarily) very bad solution as it relies on eval(), and only works on globals passed in as strings. That's a huge compromise just to work with a single argument, so practically speaking, your solution is probably better (though with the above-mentioned caveats).

A similar problem occurs with trying to imitate PHP's extract() and compact(). We don't have a way in JavaScript (unless we exclusively work with globals) to say use the arguments object to obtain or set the local variables of the caller (we can only get access to those variables explicitly passed in as arguments, and only by reference if they are objects or arrays).

I think these may well be the biggest challenges for php.js trying to follow the PHP API.

Gravatar
Brett Zamir
29 Dec '09 Permalink

q  @cynosure: Looks like someone else here tried something similar: http://phpjs.org/functions/array_pop:329#comment_354 .

As far as a reference to an array, whatever value you pass in to a function, if it is an array or object, its elements can be acted on by reference and in fact only by reference unless you manually make a copy (though you cannot replace the whole object with something else, or that does make a copy). So, we could adapt your function to work by reference (though still breaking the PHP API which only uses one argument):

function unset(array,index) {
    if (typeof array === 'object' && typeof array.length == 'number') {
        array.splice(index, 1); // Using the delete operator will replace the old value
        // with "undefined" in its old slot, but we also want to remove the slot itself,
        // so with arrays (in IE too), we can safely use splice().
    }
    else { // Objects
        delete array[index]; // For object properties, this works pretty well, except potentially in IE where
        // the property will thankfully no longer be iterated, but it has the annoying feature (for
        // the sake of our using objects to imitate PHP associative arrays) that if you later try to
        // add back a value with the same property name, it will put your new value in the old
        // iteration position.  So IE does not truly delete the property, though it may appear that way.
        // All other popular browser implementation seem to truly delete the property (and iterate
        // in order), at least if it is not an inherited property, but the latest ES spec wasn't able
        // to persuade IE to change this behavior
    }
}



See the 2nd comment above for the potential problems with this though. Basically in IE, simple objects as associative arrays just won't work perfectly. It is very disappointing. You can get around this by creating an object which wraps your data, but that can get quite ugly. Otherwise, you just have to keep your keys in one array and values in another array.

This is not to speak of our other challenge here of trying to work with only one argument in unset(). JavaScript does not allow us to get the container object or array if we only know the property. Our experimental version of unset() (at http://github.com/kvz/phpjs/blob/master/_experimental/var/unset.js ), allows us to pass in a single argument, but it is a (necessarily) very bad solution as it relies on eval(), and only works on globals passed in as strings. That's a huge compromise just to work with a single argument, so practically speaking, your solution is probably better (though with the above-mentioned caveats).

A similar problem occurs with trying to imitate PHP's extract() and compact(). We don't have a way in JavaScript (unless we exclusively work with globals) to say use the arguments object to obtain or set the local variables of the caller (we can only get access to those variables explicitly passed in as arguments, and only by reference if they are objects or arrays).

I think these may well be the biggest challenges for php.js trying to follow the PHP API.

Gravatar
Brett Zamir
29 Dec '09 Permalink

q  @cynosure: Looks like someone else here tried something similar: http://phpjs.org/functions/array_pop:329#comment_354 .

As far as a reference to an array, whatever value you pass in to a function, if it is an array or object, its elements can be acted on by reference and in fact only by reference unless you manually make a copy (though you cannot replace the whole object with something else, or that does make a copy). So, we could adapt your function to work by reference (though still breaking the PHP API which only uses one argument):

function unset(array,index) {
    if (typeof array === 'object' && typeof array.length == 'number') {
        array.splice(index, 1); // Using the delete operator will replace the old value
        // with "undefined" in its old slot, but we also want to remove the slot itself,
        // so with arrays (in IE too), we can safely use splice().
    }
    else { // Objects
        delete array[index]; // For object properties, this works pretty well, except potentially in IE where
        // the property will thankfully no longer be iterated, but it has the annoying feature (for
        // the sake of our using objects to imitate PHP associative arrays) that if you later try to
        // add back a value with the same property name, it will put your new value in the old
        // iteration position.  So IE does not truly delete the property, though it may appear that way.
        // All other popular browser implementation seem to truly delete the property (and iterate
        // in order), at least if it is not an inherited property, but the latest ES spec wasn't able
        // to persuade IE to change this behavior
    }
}



See the 2nd comment above for the potential problems with this though. Basically in IE, simple objects as associative arrays just won't work perfectly. It is very disappointing. You can get around this by creating an object which wraps your data, but that can get quite ugly. Otherwise, you just have to keep your keys in one array and values in another array.

This is not to speak of our other challenge here of trying to work with only one argument in unset(). JavaScript does not allow us to get the container object or array if we only know the property. Our experimental version of unset() (at http://github.com/kvz/phpjs/blob/master/_experimental/var/unset.js ), allows us to pass in a single argument, but it is a (necessarily) very bad solution as it relies on eval(), and only works on globals passed in as strings. That's a huge compromise just to work with a single argument, so practically speaking, your solution is probably better (though with the above-mentioned caveats).

A similar problem occurs with trying to imitate PHP's extract() and compact(). We don't have a way in JavaScript (unless we exclusively work with globals) to say use the arguments object to obtain or set the local variables of the caller (we can only get access to those variables explicitly passed in as arguments, and only by reference if they are objects or arrays).

I think these may well be the biggest challenges for php.js trying to follow the PHP API.

Gravatar
Brett Zamir
29 Dec '09 Permalink

q  @cynosure: Looks like someone else here tried something similar: http://phpjs.org/functions/array_pop:329#comment_354 .

As far as a reference to an array, whatever value you pass in to a function, if it is an array or object, its elements can be acted on by reference and in fact only by reference unless you manually make a copy (though you cannot replace the whole object with something else, or that does make a copy). So, we could adapt your function to work by reference (though still breaking the PHP API which only uses one argument):

function unset(array,index) {
    if (typeof array === 'object' && typeof array.length !== 'undefined') {
        array.splice(index, 1); // Using the delete operator will replace the old value 
        // with "undefined" in its old slot, but we also want to remove the slot itself, 
        // so with arrays (in IE too), we can safely use splice().
    }
    else { // Objects
        delete array[index]; // For object properties, this works pretty well, except potentially in IE where 
        // the property will thankfully no longer be iterated, but it has the annoying feature (for 
        // the sake of our using objects to imitate PHP associative arrays) that if you later try to 
        // add back a value with the same property name, it will put your new value in the old 
        // iteration position.  So IE does not truly delete the property, though it may appear that way.
        // All other popular browser implementation seem to truly delete the property (and iterate 
        // in order), at least if it is not an inherited property, but the latest ES spec wasn't able 
        // to persuade IE to change this behavior
    }
}



See the 2nd comment above for the potential problems with this though. Basically in IE, simple objects as associative arrays just won't work perfectly. It is very disappointing. You can get around this by creating an object which wraps your data, but that can get quite ugly. Otherwise, you just have to keep your keys in one array and values in another array.

This is not to speak of our other challenge here of trying to work with only one argument in unset(). JavaScript does not allow us to get the container object or array if we only know the property. Our experimental version of unset() (at http://github.com/kvz/phpjs/blob/master/_experimental/var/unset.js ), allows us to pass in a single argument, but it is a (necessarily) very bad solution as it relies on eval(), and only works on globals passed in as strings. That's a huge compromise just to work with a single argument, so practically speaking, your solution is probably better (though with the above-mentioned caveats).

A similar problem occurs with trying to imitate PHP's extract() and compact(). We don't have a way in JavaScript (unless we exclusively work with globals) to say use the arguments object to obtain or set the local variables of the caller (we can only get access to those variables explicitly passed in as arguments, and only by reference if they are objects or arrays).

I think these may well be the biggest challenges for php.js trying to follow the PHP API.

Gravatar
cynosure
28 Dec '09 Permalink

q  Hi!

In JS can you give a reference to an array in a function call? I need an unset() like function what can cut off an element from an array with a given index ( like unset(foo['bar']; )

My workaround is this:

function unset(array,index)
{
    var newarr = new Array();

    for(var i in array)
    {
        if(i != index) newarr[i] = array[i];
    }

    return newarr;
}



I know this is not the exact way how php's unset works, 'cos it gives only a reference to the array, and handles single variables as well as multiple variables too, but I think this can be usefull for those JS beginners like me, who wants to unset an element from an array. The delete method is buggy for me, or I don't understand how it works well.

Thanks!

Gravatar
Brett Zamir
23 Dec '09 Permalink

q  I misspoke in saying that the case in the switch is superfluous. It will indeed convert "\\0" to "\u0000" as in PHP. In any case, as I mentioned, you should add an extra '0' to the sequence (and don't add a backslash).

Gravatar
Brett Zamir
23 Dec '09 Permalink

q  @Brant: Sorry, the case in the switch is not superfluous as it will turn "\\0" into "\u0000" (as does PHP in double or single quotes). In any case, the rest of what I said still applies: don't add a backslash to "\u", just add an extra 0 at the end.

Gravatar
Brett Zamir
23 Dec '09 Permalink

q  @Brant: Thanks for letting us know. Fixed in Git. It really should be '\u0000' (was missing a zero), but it won't really make a difference either way because JavaScript already treats "\0" as "\u0000". So that case in the switch is superfluous (though I've kept it just to reflect what PHP does). FYI, "\u" is used to introduce a four-hexadecimal digit sequence in place of a Unicode character--esp. useful if you have to use non-printable characters or non-ASCII characters.

Gravatar
Brant Messenger
22 Dec '09 Permalink

q  IE7 Issue. Search for '\u000' and replace with '\\u000'.

Gravatar
Brant Messenger
22 Dec '09 Permalink

q  In a custom "wscs.namespaced.min.js" package IE7 found an error.

return false;},stripslashes:function(str){return(str+'').replace(/\\(.?)/g,function(s,n1){switch(n1){case'\\':return'\\';case'0':return'\u000';case'':return'';default:return n1;}});},stristr:function(haystack,needle,bool){var pos=0;haystack+='';pos=haystack.toLowerCase().indexOf((needle+'').toLowerCase());if(pos==-1){return false;}else{if(bool){return haystack.substr(0,pos);}else{return haystack.slice(pos);}}},strlen:function(string){var str=string+'';var i=0,chr='',lgth=0;var getWholeChar=function(str,i){var code=str.charCodeAt(i);var next='',prev='';if(0xD800<=code&&code<=0xDBFF){if(str.length<=(i+1)){throw'High surrogate without following low surrogate';}



Resolution:


return false;},stripslashes:function(str){return(str+'').replace(/\\(.?)/g,function(s,n1){switch(n1){case'\\':return'\\';case'0':return'\\u000';case'':return'';default:return n1;}});},stristr:function(haystack,needle,bool){var pos=0;haystack+='';pos=haystack.toLowerCase().indexOf((needle+'').toLowerCase());if(pos==-1){return false;}else{if(bool){return haystack.substr(0,pos);}else{return haystack.slice(pos);}}},strlen:function(string){var str=string+'';var i=0,chr='',lgth=0;var getWholeChar=function(str,i){var code=str.charCodeAt(i);var next='',prev='';if(0xD800<=code&&code<=0xDBFF){if(str.length<=(i+1)){throw'High surrogate without following low surrogate';}



Notice the difference '\u000' -> '\\u000'

Gravatar
Kevin van Zonneveld
14 Dec '09 Permalink

q  @ cynosure: Yip! Thanks for thinking of us though ; )

Gravatar
cynosure
3 Dec '09 Permalink

q  Sorry, I didn't saw that you found it already ;)

Gravatar
cynosure
3 Dec '09 Permalink

q  Hey Kevin, there are some md5() functions for JS around the web, for example this:

http://www.webtoolkit.info/javascript-md5.html

It's fast, I use it in a CRAM (challenge-response authentication) API.

Gravatar
Kevin van Zonneveld
29 Nov '09 Permalink

q  Thanks Danny, I've added a favicon : )

Gravatar
Nizam
25 Nov '09 Permalink

q  Hi Brett,

I really found this function very useful. If you don't have it, please consider this. thank you.

http://www.finefrog.com/2009/01/31/convert-a-mysql-date-string-into-javascript-date-object/

function parse_date(datetime /* YYYY-MM-DD HH:mm:ss */)
{  
	var date = new Date();  
	var parts = String(datetime).split(/[- :]/);  

	date.setFullYear(parts[0]);  
	date.setMonth(parts[1] - 1);  
	date.setDate(parts[2]);  
	date.setHours(parts[3]);  
	date.setMinutes(parts[4]);  
	date.setSeconds(parts[5]);  
	date.setMilliseconds(0);  

	return date;  
}

Download

Download

There is a wide variety of packages if the default doesn't suit you.
You can also compile your own package to avoid any overhead.

Support us

spread the word:


Use any PHP function in JavaScript


These kind folks have already donated: @HalfWinter, Paulo Freitas, Andros Peña Romo, Nitin Gupta, @nikosdion, Anonymous, Anonymous and Shawn Houser.
<your name here>

Click here to lend your support to: phpjs and make a donation at www.pledgie.com !

RSS

Tweets

Comments

Who uses php.js

If you use php.js, let us know and get linked.

Progress

php.js is complete for 82.2%

php.js on

Discuss php.js' future at Google Groups
Help improve php.js on github



Powered by php.js
Stats