Use PHP functions in JavaScript

Add Function

No expertise needed. Just JS Coding skills. We will review the code and make the changes in Git. When your code makes it into php.js you will be credited accordingly.

Add a comment with your code at the bottom of this page.

If you want you can read the Developer Guidelines that would save us some work.

Function proposals

Add Comment

Checkout PHP's implementation at: www.php.net/stream_bucket_new

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
test test
5 Jul '11 Permalink

q  

your_stuff('vicky');


Gravatar
Kevin van Zonneveld
8 Sep '10 Permalink

q  @ Brett: Guess this is their way of requesting features : )

Gravatar
Brett Zamir
3 Aug '10 Permalink

q  @Italo, @navegador: what are you guys trying to post? Did you have actual data when you submitted it or...?

Gravatar
navegador
3 Aug '10 Permalink

q  

function get_browser() {
    // Your code here
}


Gravatar
Italo
3 Aug '10 Permalink

q  

function xml_parse() {
    // Your code here
}


Gravatar
Marco Marchiò
17 Dec '09 Permalink

q  @Brett/Kevin: Harmony is a very interesting project and it's a good starting point. I think that i will start from converting it to js to parse the php code. Anyway now it's christmas time (also in Italy:D) and i don't like to work when there is the snow so i'm going to start in the 2010:D. Merry christmas and happy new year to everybody.

Gravatar
Brett Zamir
14 Dec '09 Permalink

q  @Kevin/Marco: As far as the Harmony Framework, while that can be pretty cool, that is making use of tokenizer on the server-side, while our intention is to implement that part in JavaScript also. Nevertheless, it may still be of interest.

Gravatar
Brett Zamir
14 Dec '09 Permalink

q  @Kevin: I have to agree, this looks like very good stuff (Just to check though, did you mean to redefine the variable 'i' within a loop which already was using 'i'?).

I think Tim's way with undefined is the best way though, as he is testing with "typeof". One advantage to this is that it is immune to "undefined" itself being redefined as JavaScript oddly allows. Also, if you test against undefined itself AND use a typeof, you will never get a true result because typeof always returns a string. Fixed in Git.

Gravatar
Kevin van Zonneveld
14 Dec '09 Permalink

q  @ Tim de Koning: Brilliant stuff Tim, I must say. I've added your function to our repo: http://github.com/kvz/phpjs/commit/ad6df4d48a7551b2ddc53bf03c464bdf1d49b8e4 and hence will be online shortly.

I already fixed some common jslint issues: http://github.com/kvz/phpjs/commit/5cb72f3bd9c6b624827193a2bfde24de14c0ab32 but there are still some more to tackle.

You asked for feedback; one thing I would to see - if possible - is more orthodox for-loops. You seem to perform a lot of calculations in the header of a forloop while it may just as well be possible to do them in the body.
This would allow for less jslint errors, shorter lines, and hence improved readability & maintainability.
I also noticed you check for undefined with == 'undefined'. The correct way is === undefined: this will save you some headaches to come.

There's an interesting webcast by Douglass Crockford to be found in the Developer Guidelines here: http://wiki.github.com/kvz/phpjs/developerguidelines

It's related to a lot of my points above.

Anyway, please don't feel discouraged here, I'm just trying to help you write even better JavaScript. As for your contribution: pack is a wonderful new member to php.js' arsenal. Thanks so much!

Gravatar
Kevin van Zonneveld
14 Dec '09 Permalink

q  @ Marco Marchiò: Be sure to also checkout the Harmony Framework http://www.harmony-framework.com/

Gravatar
Tim de Koning
12 Dec '09 Permalink

q  

function pack(format) {
	// Pack given arguments into binary string according to format.
    // For possible formats see  http://www.php.net/pack
    //
    // Please note: 'machine dependant byte order and size' aren't applicable for javascript
	// pack works as on a 32bit, little endian machine 
    //
    // version: 0.1
    // discuss at: http://www.kingsquare.nl/blog/12-12-2009/13507444/New-phpjs-function-pack-
    // dependancies: none
    // + original by: Tim de Koning (http://www.kingsquare.nl)
    // + original float encoding by: Jonas Raoni Soares Silva (http://jsfromhell.com/classes/binary-parser) 
    //
    // * example 1: pack("nvc*", 0x1234, 0x5678, 65, 66);
    // *     returns 1: '4xVAB';
	//
	// feedback is nice :-) phpjs-pack@kingsquare.nl

	var formatPointer, argumentPointer, result, instruction, quantifier, word, nibble;

	formatPointer = 0;
	argumentPointer = 1;
	result = '';

	while (formatPointer < format.length) {
		instruction = format[formatPointer];
		quantifier = '';
		formatPointer++;
		while((formatPointer < format.length) && (format[formatPointer].match(/[0-9\*]/) != null)) {
			quantifier += format[formatPointer];
			formatPointer++;
		}
		if (quantifier == '') quantifier = 1;
		//now pack variables: 'quantifier' times 'instruction'
		switch(instruction) {
			case 'A': //NUL-padded string
			case 'a': //SPACE-padded string
				if (typeof arguments[argumentPointer] == 'undefined') throw new Error('Warning:  pack() Type '+instruction+': not enough arguments');
				else argument = arguments[argumentPointer];
				if (quantifier=='*') quantifier = argument.length;
				for (var i=0; i<quantifier; i++) {
					if (typeof argument[i] == 'undefined') {
						if (instruction == 'a') result += "\0";
						else result += " ";
					}
					else result += argument[i];
				}
				argumentPointer++;
				break;

			case 'h': //Hex string, low nibble first
			case 'H': //Hex string, high nibble first
				if (typeof arguments[argumentPointer] == 'undefined')  throw new Error( 'Warning:  pack() Type '+instruction+': not enough arguments');
				else argument = arguments[argumentPointer];
				if (quantifier=='*') quantifier = argument.length;
				if (quantifier > argument.length) throw new Error('Warning: pack() Type '+instruction+': not enough characters in string');
				for (var i=0; i<quantifier; i+=2) {
					//always get per 2 bytes...
					word = argument[i];
					if (((i+1) >= quantifier) || typeof(argument[i+1])=='undefined') { word += "0";	}
					else word += argument[i+1];
					//the fastest way to reverse?
					if (instruction == 'h') word = word[1]+word[0];
					result += String.fromCharCode(parseInt(word, 16));
				}
				argumentPointer++;
				break;

			case 'c': //signed char
			case 'C': //unsigned char
				//c and C is the same in pack
			 	if (quantifier=='*') quantifier = arguments.length - argumentPointer;
			 	if (quantifier > (arguments.length - argumentPointer))  throw new Error('Warning:  pack() Type '+instruction+': too few arguments');

			 	for (var i=0; i<quantifier; i++) {
			 		result += String.fromCharCode(arguments[argumentPointer]);
			 		argumentPointer++
			 	}
			 	break;

			 case 's': // signed short (always 16 bit, machine byte order)
			 case 'S': // signed short (always 16 bit, machine byte order)
			 case 'v':
			 	//s and S is the same in pack
			 	//but can machine byte order be retrieved in javascript?
			 	//this is default byte order anywayz...
			 	if (quantifier=='*') quantifier = arguments.length - argumentPointer;
			 	if (quantifier > (arguments.length - argumentPointer))  throw new Error('Warning:  pack() Type '+instruction+': too few arguments');

			 	for (var i=0; i<quantifier; i++) {
			 		result += String.fromCharCode(arguments[argumentPointer]&0xFF);
			 		result += String.fromCharCode(arguments[argumentPointer]>>8&0xFF);
			 		argumentPointer++;
			 	}
			 	break;

			 case 'n': // unsigned short (always 16 bit, big endian byte order)
			 	if (quantifier=='*') quantifier = arguments.length - argumentPointer;
			 	if (quantifier > (arguments.length - argumentPointer))  throw new Error('Warning:  pack() Type '+instruction+': too few arguments');

			 	for (var i=0; i<quantifier; i++) {
			 		result += String.fromCharCode(arguments[argumentPointer]>>8&0xFF);
			 		result += String.fromCharCode(arguments[argumentPointer]&0xFF);
			 		argumentPointer++;
			 	}
			 	break;

			 case 'i': // signed integer (machine dependent size and byte order)
			 case 'I': // unsigned integer (machine dependent size and byte order)
			 case 'l': // signed long (always 32 bit, machine byte order)
			 case 'L': // unsigned long (always 32 bit, machine byte order)
			 case 'V': // unsigned long (always 32 bit, little endian byte order)
			 	if (quantifier=='*') quantifier = arguments.length - argumentPointer;
			 	if (quantifier > (arguments.length - argumentPointer))  throw new Error('Warning:  pack() Type '+instruction+': too few arguments');

			 	for (var i=0; i<quantifier; i++) {
			 		result += String.fromCharCode(arguments[argumentPointer]&0xFF);
			 		result += String.fromCharCode(arguments[argumentPointer]>>8&0xFF);
			 		result += String.fromCharCode(arguments[argumentPointer]>>16&0xFF);
			 		result += String.fromCharCode(arguments[argumentPointer]>>24&0xFF);
			 		argumentPointer++;
			 	}

			 	break;
			 case 'N': // unsigned long (always 32 bit, big endian byte order)
			 	if (quantifier=='*') quantifier = arguments.length - argumentPointer;
			 	if (quantifier > (arguments.length - argumentPointer))  throw new Error('Warning:  pack() Type '+instruction+': too few arguments');

			 	for (var i=0; i<quantifier; i++) {
			 		result += String.fromCharCode(arguments[argumentPointer]>>24&0xFF);
			 		result += String.fromCharCode(arguments[argumentPointer]>>16&0xFF);
			 		result += String.fromCharCode(arguments[argumentPointer]>>8&0xFF);
			 		result += String.fromCharCode(arguments[argumentPointer]&0xFF);
			 		argumentPointer++;
			 	}
			 	break;

			 case 'f': // float (machine dependent size and representation)
			 case 'd': // double (machine dependent size and representation)
			 	//version based on IEEE754y

			 	var precisionBits = 23, exponentBits = 8;
			 	if (instruction=='d') {
			 		precisionBits = 52 ;
			 		exponentBits = 11;
			 	}

				if (quantifier=='*') quantifier = arguments.length - argumentPointer;
			 	if (quantifier > (arguments.length - argumentPointer))  throw new Error('Warning:  pack() Type '+instruction+': too few arguments');
			  	for (var i=0; i<quantifier; i++) {

					var number = arguments[argumentPointer], bias = Math.pow(2, exponentBits - 1) - 1, minExp = -bias + 1, maxExp = bias, minUnnormExp = minExp - precisionBits, status = isNaN(n = parseFloat(number)) || n == -Infinity || n == +Infinity ? n : 0, exp = 0, len = 2 * bias + 1 + precisionBits + 3, bin = new Array(len), signal = (n = status !== 0 ? 0 : n) < 0, n = Math.abs(n), intPart = Math.floor(n), floatPart = n - intPart, i, lastBit, rounded, j, tmpResult;
			        for(i = len; i; bin[--i] = 0);
			        for(i = bias + 2; intPart && i; bin[--i] = intPart % 2, intPart = Math.floor(intPart / 2));
			        for(i = bias + 1; floatPart > 0 && i; (bin[++i] = ((floatPart *= 2) >= 1) - 0) && --floatPart);
			        for(i = -1; ++i < len && !bin[i];);
			        if(bin[(lastBit = precisionBits - 1 + (i = (exp = bias + 1 - i) >= minExp && exp <= maxExp ? i + 1 : bias + 1 - (exp = minExp - 1))) + 1]){
			            if(!(rounded = bin[lastBit])) {
			            	for(j = lastBit + 2; !rounded && j < len; rounded = bin[j++]);
			            }
			            for(j = lastBit + 1; rounded && --j >= 0; (bin[j] = !bin[j] - 0) && (rounded = 0));
			        }
			        for(i = i - 2 < 0 ? -1 : i - 3; ++i < len && !bin[i];);
			        (exp = bias + 1 - i) >= minExp && exp <= maxExp ? ++i : exp < minExp && (exp != bias + 1 - len && exp < minUnnormExp, i = bias + 1 - (exp = minExp - 1));
			        (intPart || status !== 0) && (1, exp = maxExp + 1, i = bias + 2, status == -Infinity ? signal = 1 : isNaN(status) && (bin[i] = 1));
			        for(n = Math.abs(exp + bias), j = exponentBits + 1, tmpResult = ""; --j; tmpResult = (n % 2) + tmpResult, n = n >>= 1);
			        for(n = 0, j = 0, i = (tmpResult = (signal ? "1" : "0") + tmpResult + bin.slice(i, i + precisionBits).join("")).length, r = []; i; n += (1 << j) * tmpResult.charAt(--i), j == 7 && (r[r.length] = String.fromCharCode(n), n = 0), j = (j + 1) % 8);
			        r[r.length] = n ? String.fromCharCode(n) : "";
			        result += r.join('');
					argumentPointer++;
			 	}
			 	break;

 			case 'x': //NUL byte
 				if (quantifier=='*') throw new Error('Warning: pack(): Type x: \'*\' ignored');
				for (var i=0; i<quantifier; i++) {
					result += "\0";
				}
				break;

			case 'X': //Back up one byte
				if (quantifier=='*') throw new Error('Warning: pack(): Type X: \'*\' ignored');
				for (var i=0; i<quantifier; i++) {
					if (result.length==0) {
						 throw new Error('Warning: pack(): Type X: outside of string');
					} else {
						result = result.substring(0, result.length - 1);
					}
				}
				break;

			case '@': //NUL-fill to absolute position
				if (quantifier=='*') throw new Error('Warning: pack(): Type X: \'*\' ignored');
				if (quantifier>result.length) {
					var extraNullCount = quantifier - result.length;
					for (var i=0; i<extraNullCount; i++) {
						result += "\0";
					}
				}
				if (quantifier<result.length) {
					result = result.substring(0, quantifier);
				}
				break;

			default:
				throw new Error('Warning:  pack() Type '+instruction+': unknown format code')
		}
	}
	if (argumentPointer < arguments.length) throw new Error('Warning: pack(): '+( arguments.length - argumentPointer)+' arguments unused');
	return result;
}


Gravatar
Paul Hutchinson
2 Dec '09 Permalink

q  @Brett Zamir: Thanks for the tip Brett.

Gravatar
Marco Marchiò
2 Dec '09 Permalink

q  @Brett: interesting links:) right now I've a lot of work to do but when I have time i will try to do that.

Gravatar
Brett Zamir
2 Dec '09 Permalink

q  @Marco, I've been trying to work on one myself, so I think a PHP-in-JavaScript parser is a great idea. :) (We could build it as the function token_get_all() as in the real PHP tokenizer extension.)

Among other things, it'd be great to have it to convert the PHP unit tests into php.js unit tests.

I figured it may be even cooler to parse a standard syntax like EBNF (see Wikipedia) so we could create parsers/lexers for any language which was defined in EBNF.

I found an EBNF grammar at http://www.icosaedro.it/articoli/php-syntax-ebnf.txt

I started playing around with it, then discovered Antlr, which is already meant to do this, and has a JavaScript implementation.

However, it is not documented with a lot of examples (see http://www.antlr.org/wiki/display/ANTLR3/ANTLR3JavaScriptTarget ), though there is a whole lot to read about it (http://www.antlr.org/wiki/display/ANTLR3/ANTLR+v3+printable+documentation or the tutorials at http://www.antlr.org/wiki/display/ANTLR3/Tutorials

I tried out the Expression Evaluator tool they have (see http://www.antlr.org/works/help/tutorial/calculator.html ) for download against the PHP EBNF, but after converting to a format the software recognized, I ran into some errors about parts of the EBNF being defined recursively, and I haven't had a chance to figure out how it could be resolved.

In other words, this could take a lot of time, but it would be soooo worth it if someone is interested to help out or try it out themselves.

Everything from syntax highlighters, to translators, etc. would be possible. And of course, it'd be cool to have one for JavaScript itself, though JSLint may already be a good one to use for that...

Gravatar
Marco Marchiò
1 Dec '09 Permalink

q  @Brett: what do you think about creating a php parser written in javascript, so that you can use the PHP sintax (especially classes) to generate the relative js code?

Gravatar
Brett Zamir
30 Nov '09 Permalink

q  By the way, if anyone has any outstanding issues (besides the recent items for date() which I've already added to our tracker, and besides the error_log() and asort() issues which I have on my todo list), please let us know so we can try to make sure we are 100% tracking all outstanding issues...

Gravatar
Brett Zamir
30 Nov '09 Permalink

q  @Kankrelune : Doesn't look like I told you that I added your reimplementation for version_compare... Thanks!

Gravatar
Brett Zamir
29 Nov '09 Permalink

q  @Paul: That sounds like a good idea. I'd like to take a closer look when I have some time. As far as file writing, I've started a "file_put_contents()" implementation for use in Mozilla extensions, but we can adapt it to alternatively work for making Ajax POST or PUT requests (as well as make it work with CommonJS SSJS potentially too). We can use the stream context argument to do any configuration (e.g., to work with Mozilla file writing instead of Ajax POST or whatever).

Btw, one JavaScript gotcha to look out for (at least for us PHP devs) is that you can't test for "console" as you did; if it doesn't exist, it will cause an error that causes the script to stop. You either have to make the check as a try-catch block, or test it as a property (i.e., "if (window.console) ...").

Gravatar
Paul Hutchinson
26 Nov '09 Permalink

q  Most browsers now support basic console.log() so it would be helpful to output error_log() to this.

I don't see a way to support email or file logging, but basic console.log() would be a good start.

function error_log(message,message_type,destination,extra_headers)
{
    if(typeof(console) === 'undefined' || console == null)
        return;

    if(message_type==null)
        message_type=0;
    switch(message_type)
    {
        case 0: // console
        case 4: // SAPI logging
            console.log(message);
        break;
        case 1: // email
            console.log(message);
        break;
        case 2: // nothing
        break;
        case 3: // file logging
            if(console.group!=null)
                console.group(destination);
            console.log(message);
            if(console.groupEnd!=null)
                console.groupEnd();
        break;
    }
}


Gravatar
Brett Zamir
20 Nov '09 Permalink

q  Also please note I just made another commit now which removed a trailing comma (needed for IE) in the initial OPTS assignment.

Gravatar
Brett Zamir
20 Nov '09 Permalink

q  Hi Marco,

Ok, now looks great, thanks! I added a couple other test cases and they passed too. I also added some code toward the beginning to allow flags to be passed in as bitwise-OR'd numbers, a single-item string, or an array of strings (yours allowed multiple flags to be space-separated in a single string, but to avoid potential conflicts, I think we should stick with arrays and bitwise-OR'd numbers for this). The commit is at http://github.com/kvz/phpjs/commit/9e36e6a87aae3cbfbeb98890a2775d479297d735

However, it's up to Kevin as to whether this should be moved to the main /functions directory (and category) at this point since our preg functions do not support all of the flags and syntax of PHP regular expressions such as Unicode character classes as in a good many cases these could in fact be added, such as in the very good XRegExp package.

We could just release the preg functions for now as long as they implement all of the function arguments (at least preg_split() already does) and just hope that they will later be improved to support more of the PCRE syntax and flags.

Gravatar
Marco Marchiò
19 Nov '09 Permalink

q  @Brett: i've finally solved the problem and correct another bug. Now every test works.

function preg_split (pattern, subject, limit, flags) {
    // http://kevin.vanzonneveld.net
    // + original by: Marco Marchi?
    // * example 1: preg_split(/[\s,]+/, "hypertext language, programming");
    // * returns 1: [hypertext, language, programming]
    // * example 2: preg_split('//', 'string', -1, 'PREG_SPLIT_NO_EMPTY');
    // * returns 2:
    // * example 3: var str = 'hypertext language programming';
    // * example 3: preg_split('/ /', str, -1, 'PREG_SPLIT_OFFSET_CAPTURE');
    // * returns 3:
 
// First example still causing infinite loop!
 
    limit = limit || 0; flags = flags || ''; // Limit and flags are optional
    var result, ret=[], index=0, i = 0,
        noEmpty = flags.indexOf("PREG_SPLIT_NO_EMPTY") !== -1,
        delim = flags.indexOf("PREG_SPLIT_DELIM_CAPTURE") !== -1,
        offset = flags.indexOf("PREG_SPLIT_OFFSET_CAPTURE") !== -1,
        regexpBody=/^\/(.*)\/\w*$/.exec(pattern.toString())[1],
        regexpFlags=/^\/.*\/(\w*)$/.exec(pattern.toString())[1];
        // Non-global regexp causes an infinite loop when executing the while,
        // so if it's not global, copy the regexp and add the "g" modifier.
        pattern=pattern.global && typeof pattern!="string" ? pattern :
            new RegExp(regexpBody, regexpFlags+(regexpFlags.indexOf("g")!==-1 ? "":"g"));
    var _filter = function(str,strindex) {
        // If the match is empty and the PREG_SPLIT_NO_EMPTY flag is set don't add it
        if(noEmpty && !str.length) {return;}
        // If the PREG_SPLIT_OFFSET_CAPTURE flag is set
        // transform the match into an array and add the index at position 1
        if(offset) {str = [str,strindex];}
        ret.push(str);
    };
    //Special case for empty regexp
    if(!regexpBody){
        result=subject.split("");
        for(i=0;i<result.length;i++) {
            _filter(result[i],i);
        }
        return ret;
    }
    // Exec the pattern and get the result
    while(result = pattern.exec(subject)) {
        // Stop if the limit is 1
        if (limit === 1) {break;}
        // Take the correct portion of the string and filter the match
        _filter(subject.slice(index, result.index), index);
        index = result.index+result[0].length;
        // If the PREG_SPLIT_DELIM_CAPTURE flag is set every capture match must be included in the results array
        if(delim) {
            // Convert the regexp result into a normal array
            var resarr = Array.prototype.slice.call(result);
            for(i = 1; i < resarr.length; i++) {
                if(result[i] !== undefined) {
                    _filter(result[i], result.index+result[0].indexOf(result[i]));
                }
            }
        }
        limit--;
    }
    // Filter last match
    _filter(subject.slice(index, subject.length), index);
    return ret;
}

Gravatar
Brett Zamir
18 Nov '09 Permalink

q  @Marco: Here ya go... (Btw, I'd debug it myself, but busy and have a cold)

<script>

alert(preg_split(/[\s,]+/, "hypertext language, programming"));

function preg_split (pattern, subject, limit, flags) {
    // http://kevin.vanzonneveld.net
    // + original by: Marco Marchi?
    // * example 1: preg_split(/[\s,]+/, "hypertext language, programming");
    // * returns 1: 'hypertext,language,programming' 
    limit = limit || 0; flags = flags || ''; //Limit and flags are optional
    var result, ret=[], index=0, i = 0,
        noEmpty = flags.indexOf("PREG_SPLIT_NO_EMPTY") !== -1,
        delim = flags.indexOf("PREG_SPLIT_DELIM_CAPTURE") !== -1,
        offset = flags.indexOf("PREG_SPLIT_OFFSET_CAPTURE") !== -1,
                regexpBody=/^\/(.*)\/\w*$/.exec(pattern.toString())[1], 
                regexpFlags=/^\/.*\/(\w*)$/.exec(pattern.toString())[1];
                //non global regexp cause a infinite loop when executing the while,
                //so if it's not global copy the regexp and add the "g" modifier.
                pattern=pattern.global || typeof pattern!="string" ? pattern : 
                                new RegExp(regexpBody,regexpFlags+(regexpFlags.indexOf("g")!==-1 ? "":regexpFlags+"g"));        
    var _filter = function(str,strindex) {
        // If the match is empty and the PREG_SPLIT_NO_EMPTY flag is set don't add it
        if(noEmpty && !str.length) {return;}        // If the PREG_SPLIT_OFFSET_CAPTURE flag is set
        // transform the match into an array and add the index at position 1
        if(offset) {str = [str,strindex];}
        ret.push(str);
    };        
        //Special case for empty regexp
        if(!regexpBody){
                var result=subject.split("");
                for(i=0;i<result.length;i++) _filter(result[i],i);
                return ret;        }
    // Exec the pattern and get the result
var ctr=0;
    while(result = pattern.exec(subject)) {
    if (++ctr > 100) {break;}
        // Stop if the limit is 1
        if (limit === 1) {break;}        // Take the correct portion of the string and filter the match
        _filter(subject.slice(index, result.index), index);
        index = result.index+result[0].length;
        // If the PREG_SPLIT_DELIM_CAPTURE flag is set every capture match must be included in the results array
        if(delim) {            // Convert the regexp result into a normal array
            var resarr = Array.prototype.slice.call(result);
            for(i = 1; i < resarr.length; i++) {
                if(result[i] !== undefined) {
                    _filter(result[i], result.index+result[0].indexOf(result[i]));                }
            }
        }
        limit--;
    }
    // Filter last match
    _filter(subject.slice(index, subject.length), index);
    return ret;
}

</script>

Gravatar
Marco Marchiò
18 Nov '09 Permalink

q  @Brett: I've done every test again in Firefox, IE7, IE6, Opera, Chrome and Safari and i haven't found any infinite loop. This time i have taken the copy of the function from github so it's correct. I'm sorry but i can't get the error you're talking about. Can you write the code that you use when you get the infinite loop?

Gravatar
Brett Zamir
18 Nov '09 Permalink

q  @Marco: I am using the exact code you have below in Firefox, and it will run into an infinite loop with the first example you have listed there... Is it possible something was stripped out of your code by our comments system--if you test in Firefox against that code as it is there, you should see it also creates an infinite loop (though I'd put a limit in the while loop so your browser doesn't lock up)...

Gravatar
Marco Marchiò
17 Nov '09 Permalink

q  @Brett: i've done all tests with the last function that i've posted and they are all correct, so please try again. Remember that in js when you pass a string as a regex you must use the double escape char ( \s become \\s ), maybe you forgot it when you have done your tests because i don't get any error and i don't understand why you still getting an infinite loop.

Gravatar
Brett Zamir
15 Nov '09 Permalink

q  @Marco: I'm still getting infinite loops on the first example. Please test all tests and make sure all three are working. If you are using Firefox, I would suggest https://addons.mozilla.org/en-US/firefox/addon/7434 and its XUL Editor or JS Env for doing JavaScript tests . Also, I'm not sure why, but the line returns are getting messed up--is that something you are doing or is the comment code at this site? Also, please use http://github.com/kvz/phpjs/blob/master/_workbench/pcre/preg_split.js . Thanks!

Gravatar
Marco Marchiò
13 Nov '09 Permalink

q  @Brett Zamir: I've fixed the infinite loop bug and done other tests. I think it works perfect now.

function preg_split (pattern, subject, limit, flags) {
    // http://kevin.vanzonneveld.net
    // + original by: Marco Marchi?
    // * example 1: preg_split(/[\s,]+/, "hypertext language, programming");
    // * returns 1: 'hypertext,language,programming'
 
    limit = limit || 0; flags = flags || ''; //Limit and flags are optional
    var result, ret=[], index=0, i = 0,
        noEmpty = flags.indexOf("PREG_SPLIT_NO_EMPTY") !== -1,
        delim = flags.indexOf("PREG_SPLIT_DELIM_CAPTURE") !== -1,
        offset = flags.indexOf("PREG_SPLIT_OFFSET_CAPTURE") !== -1,
		regexpBody=/^\/(.*)\/\w*$/.exec(pattern.toString())[1], 
		regexpFlags=/^\/.*\/(\w*)$/.exec(pattern.toString())[1];
		//non global regexp cause a infinite loop when executing the while,
		//so if it's not global copy the regexp and add the "g" modifier.
		pattern=pattern.global || typeof pattern!="string" ? pattern : 
				new RegExp(regexpBody,regexpFlags+(regexpFlags.indexOf("g")!==-1 ? "":regexpFlags+"g"));	
    var _filter = function(str,strindex) {
        // If the match is empty and the PREG_SPLIT_NO_EMPTY flag is set don't add it
        if(noEmpty && !str.length) {return;}
        // If the PREG_SPLIT_OFFSET_CAPTURE flag is set
        // transform the match into an array and add the index at position 1
        if(offset) {str = [str,strindex];}
        ret.push(str);
    };
	//Special case for empty regexp
	if(!regexpBody){
		var result=subject.split("");
		for(i=0;i<result.length;i++) _filter(result[i],i);
		return ret;
	}
    // Exec the pattern and get the result
    while(result = pattern.exec(subject)) {
        // Stop if the limit is 1
        if (limit === 1) {break;}
        // Take the correct portion of the string and filter the match
        _filter(subject.slice(index, result.index), index);
        index = result.index+result[0].length;
        // If the PREG_SPLIT_DELIM_CAPTURE flag is set every capture match must be included in the results array
        if(delim) {
            // Convert the regexp result into a normal array
            var resarr = Array.prototype.slice.call(result);
            for(i = 1; i < resarr.length; i++) {
                if(result[i] !== undefined) {
                    _filter(result[i], result.index+result[0].indexOf(result[i]));
                }
            }
        }
        limit--;
    }
    // Filter last match
    _filter(subject.slice(index, subject.length), index);
    return ret;
}

Gravatar
Brett Zamir
11 Nov '09 Permalink

q  @Marco: Not yet. Getting another infinite loop trying the second example:

preg_split('//', 'string', -1, 'PREG_SPLIT_NO_EMPTY');



Maybe it's because it's empty, haven't looked carefully at it.

Here's the third one to try too:

var str = 'hypertext language programming';
var chars = preg_split('/ /', str, -1, 'PREG_SPLIT_OFFSET_CAPTURE');



and make sure it follows that in the docs at http://www.php.net/manual/en/function.preg-split.php

Please, if you would, use this version to work off of in the future since I cleaned it up a little superficially:
http://github.com/kvz/phpjs/blob/master/_workbench/pcre/preg_split.js

Thanks!

Gravatar
Brett Zamir
9 Nov '09 Permalink

q  @Ben Shelock: That was a nice attempt for someone who describes themselves as an amateur, so thanks for offering! However, in order to emulate the function PHP fully, which allows special treatment of C-escape sequences, which sometimes makes octal escapes, and allows ranges of characters, there is a good bit more which needed to be done. I had already begun an implementation on this earlier, and it is now finished at http://github.com/kvz/phpjs/blob/master/functions/strings/addcslashes.js thanks to your prompting... :)

Gravatar
Marco Marchiò
9 Nov '09 Permalink

q  Fixed the infinite loop bug:

function preg_split(pattern,subject,limit,flags)
{
        var limit=limit || 0, flags=flags || "", //Limit and flags are optional
        result, ret=new Array(), index=0,
		//non global regexp cause a infinite loop when executing the while,
		//so if it's not global copy the regexp and add the "g" modifier
		pattern=pattern.global? pattern : new RegExp(/^\/(.*)\/\w*$/.exec(pattern.toString())[1],/^\/.*\/(\w*)$/.exec(pattern.toString())[1]+"g"),
        noEmpty=flags.indexOf("PREG_SPLIT_NO_EMPTY")!=-1,        delim=flags.indexOf("PREG_SPLIT_DELIM_CAPTURE")!=-1,
        offset=flags.indexOf("PREG_SPLIT_OFFSET_CAPTURE")!=-1,
        filter=function(str,strindex){
			//If the match is empty and the PREG_SPLIT_NO_EMPTY flag is set dont'add it
			if(noEmpty && !str.length) return; 
			//If the PREG_SPLIT_OFFSET_CAPTURE flag is set transform the match into an array and add the index at position 1			
			if(offset) str=new Array(str,strindex);
			ret.push(str);
        };
        //Exec the pattern and get the result        
		while(result=pattern.exec(subject)) {
			//Stop if the limit is 1
			if(limit==1) break;
			//Take the correct portion of the string and filter the match
			filter(subject.slice(index,result.index),index);               
			index=result.index+result[0].length;
			//If the PREG_SPLIT_DELIM_CAPTURE flag is set every capture match must be included in the results array
			if(delim)
			{
					//Convert the regexp result into a normal array                        
					var resarr=Array.prototype.slice.call(result);
					for(i=1;i<resarr.length;i++)
							if(result[i]!==undefined) filter(result[i],result.index+result[0].indexOf(result[i]));                  
			}
			limit--;        
		}
        //Filter last match
        filter(subject.slice(index,subject.length),index);
        return ret;
}

Gravatar
Marco Marchiò
9 Nov '09 Permalink

q  @Brett Zamir: I can't see the test but when i have done my tests i remember that i found that bug too, but it's not an error in the code. It is produced by regexp that are not global (no G modifier), with those regexp the while loop become infinite. I try to solve the problem now.

Gravatar
Ben Shelock
9 Nov '09 Permalink

q  

function addcslashes(str, charlist){
    // Escapes characters defined in charlist
    // 
    // version: 1
    // discuss at: http://phpjs.org/functions/addcslashes
    // +   original by: Ben Shelock
    // %        note 1: Developed by a javascript amature, forgive me.
    // *     example 1: addcslashes('Something', 'oei');
    // *     returns 1: S\om\eth\ing

    var charlist = charlist.split(""), string = '';
    for(var i = 0; i < str.length; i++){
        if(in_array(str[i], charlist)){
            string = string+'\\'+str[i];
        }
        else{
            string = string+str[i];
        }
    }
    return string;
}


Gravatar
Brett Zamir
7 Nov '09 Permalink

q  @Marco: Thanks for the function (it would be a great one to have), and I added it to our workbench area, but it looks like there is still at least one bug needing fixing. If you use the example I added at http://github.com/kvz/phpjs/blob/8f2086ef2577bc81486a3f96d6a850e2b2d82b03/_workbench/pcre/preg_split.js it runs in an infinite loop.

Gravatar
Marco Marchiò
5 Nov '09 Permalink

q  

function preg_split(pattern,subject,limit,flags)
{
	var limit=limit || 0, flags=flags || "", //Limit and flags are optional
	result, ret=new Array(), index=0,
	noEmpty=flags.indexOf("PREG_SPLIT_NO_EMPTY")!=-1,
	delim=flags.indexOf("PREG_SPLIT_DELIM_CAPTURE")!=-1,
	offset=flags.indexOf("PREG_SPLIT_OFFSET_CAPTURE")!=-1,
	filter=function(str,strindex){
		//If the match is empty and the PREG_SPLIT_NO_EMPTY flag is set dont'add it
		if(noEmpty && !str.length) return;
		//If the PREG_SPLIT_OFFSET_CAPTURE flag is set transform the match into an array and add the index at position 1
		if(offset) str=new Array(str,strindex);
		ret.push(str);
	};
	//Exec the pattern and get the result
	while(result=pattern.exec(subject)) {
		//Stop if the limit is 1
		if(limit==1) break;
		//Take the correct portion of the string and filter the match
		filter(subject.slice(index,result.index),index);
		index=result.index+result[0].length;
		//If the PREG_SPLIT_DELIM_CAPTURE flag is set every capture match must be included in the results array
		if(delim)
		{
			//Convert the regexp result into a normal array
			var resarr=Array.prototype.slice.call(result);
			for(i=1;i<resarr.length;i++)
				if(result[i]!==undefined) filter(result[i],result.index+result[0].indexOf(result[i]));			
		}
		limit--;
	}
	//Filter last match
	filter(subject.slice(index,subject.length),index);
	return ret;
}


Gravatar
Brett Zamir
29 Jun '09 Permalink

q  Ok, it is now added in SVN and passing all tests. Thanks very much for this one!

Gravatar
Greg Frazier
26 Jun '09 Permalink

q  Honestly, I wrote this function several months ago for a project and discovered it would be easier if I implemented it in PL/SQL. I recently found it in some old files, tested it using the same test that Apache uses for their metaphone function and fixed any errors that I found (passes 238 tests out of 244, although PHP's implementation isn't without errors either)
I have it up here if you want to see it: http://gregoryfrazier.com/metaphone2.html

When I wrote it, I spent very little time on it, it's quite a hack job, thats why I'm saying I'm sure there are bugs. I don't know when I'd have time next to debug it; so I thought I'd just post it up here for someone else to look at and play around with, or else it would just rot on my hard drive.

As for the String() question, I vaguely remember something about Internet Explorer 6 giving me errors unless it was done that way. I have no idea, it doesn't make sense to me, but who knows?

As for the second argument, yeah that wouldn't be hard at all. Just change return to:

return metaword.substr(0,phones);


With some error checking to make sure it's an integer or parseInt it or whatever.

Gravatar
Kevin van Zonneveld
26 Jun '09 Permalink

q  @ Greg Frazier + Brett Zamir: this is really great! one of the missing string functions, good job!

Gravatar
Brett Zamir
26 Jun '09 Permalink

q  @Greg Frazier, Wow, very nice work!

I did a little bit of jslint.com - assisted clean-up, added examples, and fixed one bug (metaword spelled as metword in one place), so please use this version in the future: http://trac.phpjs.org/projects/phpjs/browser/trunk/_workbench/strings/metaphone.js (you can download as text via a link at the bottom of the page)

I haven't looked at the code closely, but are all those uses of the String() object wrapper necessary?

Also, would there be any way to implement the second argument "phones" (for maximum phonemes according to the PHP source)?

When you say there are bugs, can you give test cases/examples? Otherwise, I'd love for us to be able to release this out of the workbench area...

Thanks again, really great to have this one!

Gravatar
Greg Frazier
26 Jun '09 Permalink

q  There are bugs, but in my testing, it's very accurate.

function metaphone(word){
	var wordlength = word.length;
	var x = 0, tempchar = "";
	var metaword = "";
	var removedbl = function(word){
		var wordlength = word.length;
		var tempword = word.toLowerCase();
		var rebuilt;
		var tempchar1, tempchar2;
		var x;
		
		tempchar1 = String(tempword).charAt(0);				
		rebuilt = tempchar1;
		for(x=1;x<wordlength;x++){
			tempchar2 = String(tempword).charAt(x)
			if(tempchar2 != tempchar1 || tempchar2 == 'c' || tempchar2 == 'g'){
				rebuilt += tempchar2;
			}
			tempchar1 = tempchar2;
		}
		return rebuilt;
	}
	var isVowel=function(a){
		switch(a.toLowerCase())
		{
			case 'a': return true; break;
			case 'e': return true; break;
			case 'i': return true; break;
			case 'o': return true; break;
			case 'u': return true; break;
			default: return false; break;
		}
	};
	var tempword = removedbl(word.toLowerCase());
	
	//Special wh- case
	if(String(tempword).charAt(0) == 'w' && String(tempword).charAt(1) == 'h'){
		// Remove "h" and rebuild the string
		tempword = "w" + String(tempword).substr(2);
	}
	
	for(x=0; x<wordlength; x++){
		tempchar = String(tempword).charAt(x)
		if(x == 0 && x+1 <= wordlength){
			switch(tempchar){
				case 'a': if(String(tempword).charAt(x+1) == 'e'){ metaword += 'e'; }else{metaword += 'a';} break;
				case 'e': metaword += 'e'; break;
				case 'i': metaword += 'i'; break;
				case 'o': metaword += 'o'; break;
				case 'u': metaword += 'u'; break;							
				case 'g': if(String(tempword).charAt(x+1) == 'n'){ x += 1; tempchar = String(tempword).charAt(x);} break;
				case 'k': if(String(tempword).charAt(x+1) == 'n'){ x += 1; tempchar = String(tempword).charAt(x);} break;
				case 'p': if(String(tempword).charAt(x+1) == 'n'){ x += 1; tempchar = String(tempword).charAt(x);} break;
				case 'w': if(String(tempword).charAt(x+1) == 'r'){ x += 1; tempchar = String(tempword).charAt(x); break;} break;
			}
		}
		if(isVowel(tempchar) == false){
			switch(tempchar){
				case 'b': if(String(tempword).charAt(x-1) == 'm'){ break;}else{metaword += 'b';} break;
				case 'c': if(x+1 <= wordlength){
							if(String(tempword).charAt(x+1) == 'h' && String(tempword).charAt(x-1) != 's'){ metaword += 'x'; }else if(String(tempword).charAt(x+1) == 'i' && String(tempword).charAt(x+2) == 'a'){ metaword += 'x';}
							else if(String(tempword).charAt(x+1) == 'i' || String(tempword).charAt(x+1) == 'e' || String(tempword).charAt(x+1) == 'y'){ 
								if(x > 0){
									if(String(tempword).charAt(x-1) == 's'){
										break;
									}else{
										metaword += 's'; 
									}
								}else{
									metaword += 's'; 
								}
							}else{
								metaword += 'k';
							}
						  }else{
							metaword += 'k';
						  }
						  break;
				case 'd': if(x+2 <= wordlength){
							if(String(tempword).charAt(x+1) == 'g'){ 
								if(String(tempword).charAt(x+2) == 'e' || String(tempword).charAt(x+2) == 'y' || String(tempword).charAt(x+2) == 'i'){ 
									metaword += 'j';
									x += 2;
								}else{
									metaword += 't';
								}
							}else{
								metaword += 't';
							}
						  }else{
								metaword += 't';
						  }
						  break;
				case 'f': metaword += 'f'; break;
				case 'g': if(x < wordlength){
							if((String(tempword).charAt(x+1) == 'n' && x+1 == wordlength - 1) || (String(tempword).charAt(x+1) == 'n' && String(tempword).charAt(x+2) == 's' && x+2 == wordlength - 1)){break;}
							if(String(tempword).charAt(x+1) == 'n' && String(tempword).charAt(x+2) == 'e' && String(tempword).charAt(x+3) == 'd' && x+3 == wordlength - 1){break;}
							if(String(tempword).charAt(x-1) == 'n' && String(tempword).charAt(x-2) == 'i' && x == wordlength - 1){break;}
							if(String(tempword).charAt(x+1) == 'h' && x+1 <= wordlength-1 && String(tempword).charAt(x-1) == 'u' && String(tempword).charAt(x-2) == 'o'){metaword += 'f';break;}
							if(String(tempword).charAt(x+1) == 'h' && x+2 <= wordlength){if(isVowel(String(tempword).charAt(x+2)) == false){break; /*silent*/ }else{metaword += 'k';}}
							else if(x+1 == wordlength){if(String(tempword).charAt(x+1) == 'n'){break;}else{metaword += 'k';}}
							else if(x+3 == wordlength){if(String(tempword).charAt(x+1) == 'n' && String(tempword).charAt(x+2) == 'e' && String(tempword).charAt(x+3) == 'd'){;}else{metaword += 'k';}}
							else if(x+1 <= wordlength){if(String(tempword).charAt(x+1) == 'i' || String(tempword).charAt(x+1) == 'e' || String(tempword).charAt(x+1) == 'y'){
													if(String(tempword).charAt(x-1) != 'g'){ metaword += 'j';}
													}else if(x > 0){ if(String(tempword).charAt(x-1) == 'd'){
														switch(String(tempword).charAt(x+1)){
															case 'e':
															case 'y':
															case 'i': break;
															default: metaword += 'k';																	
														}
														}else{metaword += 'k';}
													}else{metaword += 'k';}
							}else{
								metaword += 'k';
							}
						  }else{
								metaword += 'k';
						  }
						  break;
				case 'm': metaword += 'm'; break;
				case 'j': metaword += 'j'; break;
				case 'n': metaword += 'n'; break;
				case 'q': metaword += 'k'; break;
				case 'r': metaword += 'r'; break;
				case 'l': metaword += 'l'; break;
				case 'v': metaword += 'f'; break;
				case 'z': metaword += 's'; break;
				case 'x': if(x == 0){metaword += 's';}else{metaword += 'ks';} break;
				case 'm': metaword += 'm'; break;
				case 'k': if(x > 0){ if(String(tempword).charAt(x-1) != 'c'){metaword += 'k';}}else{metaword += 'k';} break;
				case 'p': if(x+1 <= wordlength){if(String(tempword).charAt(x+1) == 'h'){metaword += 'f';}else{metaword +='p';}}else{metaword += 'p';} break;
				case 'y': if(x+1 <= wordlength){if(isVowel(String(tempword).charAt(x+1)) == true){metaword += 'y';}}else{metword += 'y';} break;
				case 'h': if(x > 0){ if(isVowel(String(tempword).charAt(x-1)) == true){
										if(isVowel(String(tempword).charAt(x+1)) == true){metaword += 'h'; break;}
										break;
									}
										switch(String(tempword).charAt(x-1)){
											case 'c':
											case 's':
											case 'p':
											case 't':
											case 'g': break;
											default: metaword += 'h';
										}
									}else{
										metaword += 'h';
									}
									break;
				case 's': if(x+1 <= wordlength){if(String(tempword).charAt(x+1) == 'h'){ metaword += 'x'; }
							else if(x+2 <= wordlength){if(String(tempword).charAt(x+1) == 'i'){if(String(tempword).charAt(x+2) == 'o' || String(tempword).charAt(x+2) == 'a'){metaword += 'x';}else{metaword += 's';}
							}else{metaword += 's';}}else{metaword += 's';}}else{metaword += 's';} break;
				case 't': if(x+1 <= wordlength){if(String(tempword).charAt(x+1) == 'h'){ metaword += '0'; }
							else if(x+2 <= wordlength){if(String(tempword).charAt(x+1) == 'i'){if(String(tempword).charAt(x+2) == 'o' || String(tempword).charAt(x+2) == 'a'){metaword += 'x';}else{metaword += 't';}
							}else{metaword += 't';}}else{metaword += 't';}}else{metaword += 't';} break;
				case 'w': if(x+1 <= wordlength){if(isVowel(String(tempword).charAt(x+1)) == true){metaword += 'w'}} break;
			}
		}
	}
	return metaword;
}


Gravatar
Brett Zamir
20 Jun '09 Permalink

q  @jhkkhkj: Thanks for the input, but we'd really want it to work like in PHP. Although it's not documented in PHP yet, and it might not be implemented perfectly, I think, based on a quick look at the source, that it should be working now basically as it does in PHP: http://phpjs.org/functions/class_alias

Gravatar
jhkkhkj
20 Jun '09 Permalink

q  

function class_alias() {
    // Your code here
}


Gravatar
Kankrelune
30 May '09 Permalink

q  http://www.webfaktory.info/version_compare.txt

Sorry for multiple post... .. .

@ tchaOo°

Gravatar
Kankrelune
30 May '09 Permalink

q  Why the code is not complete... .. ?

a last test...

function version_compare(version1, version2, operator)
{
    if (!version1)
        return;
    if (!version2)
        return;

    var v1, v2, compare = 0, i = 0, x = 0;
    var standardise = function(v) {
        v = v.replace(/(^\s*)|(\s*$)/g, "").replace(/[-|_|+]/g,'.').replace(/([^0-9\.]+)/g,'.$1.');
        return v.replace(/\.\.*/g,'.').split('.');
    };
    var versions = {
        'dev'   : 0,
        'alpha' : 1,
        'a'     : 1,
        'beta'  : 2,
        'b'     : 2,
        'rc'    : 3,
        '#'     : 4,
        'p'     : 5,
        'pl'    : 5
    };
    
    v1 = standardise(version1);
    v2 = standardise(version2);
    while (!v1[0]) { v1.shift(); }
    while (!v2[0]) { v2.shift(); }
    while (!v1[v1.length-1]) { v1.pop(); }
    while (!v2[v2.length-1]) { v2.pop(); }
    x = (v1.length > v2.length) ? v2.length : v1.length;
    
    for (i = 0; i < x; i++) {
        if (v1[i] == v2[i]) 
            continue;
        
        i1 = v1[i];
        i2 = v2[i];
        
        if (!isNaN(i1) && !isNaN(i2)) {
            compare = (parseInt(i1) < parseInt(i2)) ? -1 : 1;
            break;
        }
        
        if (i1 == '#')
            i1 = '';
                else if (!isNaN(i1))
                    i1 = '#';
        
        if (i2 == '#')
            i2 = '';
                else if (!isNaN(i2))
                    i2 = '#';
        
        i1 = i1.toLowerCase();
        i2 = i2.toLowerCase();
        if (versions[i1] && versions[i2])
           compare = (versions[i1] < versions[i2]) ? -1 : 1;
        else if (versions[i1])
            compare = 1;
        else if (versions[i2])
            compare = -1;
        else
            compare = 0;
        
        break;
    }
    if (compare == 0) {
        if (v2.length > v1.length) {
            if (versions[v2[i].toLowerCase()])
                compare = (versions[v2[i].toLowerCase()] < 4) ? 1 : -1;
                    else
                        compare = -1;
        } 
        else if (v2.length < v1.length) {
            if (versions[v1[i].toLowerCase()])
                compare = (versions[v1[i].toLowerCase()] < 4) ? -1 : 1;
                    else
                        compare = 1;
        }
            
    }
    if (operator) {
        switch (operator) {
            case '>':
            case 'gt':
                return (compare > 0);
            case '>=':
            case 'ge':
                return (compare >= 0);
            case '<=':
            case 'le':
                return (compare <= 0);
            case '==':
            case '=':
            case 'eq':
                return (compare == 0);
            case '<>':
            case '!=':
            case 'ne':
                return (compare != 0);
            case '':
            case '<':
            case 'lt':
            default:
                return (compare < 0);
        }
    }
    return compare;
}



if the code is not complete mail me for a complete version... sorry for the flood... .. .

@ tchaOo°

Gravatar
Kankrelune
30 May '09 Permalink

q  Ô_o

function version_compare(version1, version2, operator)
{
    if (!version1)
        return;
    if (!version2)
        return;

    var v1, v2, compare = 0, i = 0, x = 0;
    var standardise = function(v) {
        v = v.replace(/(^\s*)|(\s*$)/g, "").replace(/[-|_|+]/g,'.').replace(/([^0-9\.]+)/g,'.$1.');
        return v.replace(/\.\.*/g,'.').split('.');
    };
    var versions = {
        'dev'   : 0,
        'alpha' : 1,
        'a'     : 1,
        'beta'  : 2,
        'b'     : 2,
        'rc'    : 3,
        '#'     : 4,
        'p'     : 5,
        'pl'    : 5
    };
    
    v1 = standardise(version1);
    v2 = standardise(version2);
    while (!v1[0]) { v1.shift(); }
    while (!v2[0]) { v2.shift(); }
	while (!v1[v1.length-1]) { v1.pop(); }
    while (!v2[v2.length-1]) { v2.pop(); }
    x = (v1.length > v2.length) ? v2.length : v1.length;
    
    for (i = 0; i < x; i++) {
        if (v1[i] == v2[i]) 
            continue;
        
        i1 = v1[i];
        i2 = v2[i];
        
        if (!isNaN(i1) && !isNaN(i2)) {
            compare = (parseInt(i1) < parseInt(i2)) ? -1 : 1;
            break;
        }
        
        if (i1 == '#')
            i1 = '';
                else if (!isNaN(i1))
                    i1 = '#';
        
        if (i2 == '#')
            i2 = '';
                else if (!isNaN(i2))
                    i2 = '#';
        
		i1 = i1.toLowerCase();
		i2 = i2.toLowerCase();
        if (versions[i1] && versions[i2])
           compare = (versions[i1] < versions[i2]) ? -1 : 1;
        else if (versions[i1])
            compare = 1;
        else if (versions[i2])
            compare = -1;
        else
            compare = 0;
		
        break;
    }
    if (compare == 0) {
        if (v2.length > v1.length) {
            if (versions[v2[i].toLowerCase()])
                compare = (versions[v2[i].toLowerCase()] < 4) ? 1 : -1;
                    else
                        compare = -1;
        } 
        else if (v2.length < v1.length) {
            if (versions[v1[i].toLowerCase()])
                compare = (versions[v1[i].toLowerCase()] < 4) ? -1 : 1;
                    else
                        compare = 1;
        }
			
    }
    if (operator) {
        switch (operator) {
            case '>':
            case 'gt':
                return (compare > 0);
            case '>=':
            case 'ge':
                return (compare >= 0);
            case '<=':
            case 'le':
                return (compare <= 0);
            case '==':
            case '=':
            case 'eq':
                return (compare == 0);
            case '<>':
            case '!=':
            case 'ne':
                return (compare != 0);
            case '':
            case '<':
            case 'lt':
            default:
                return (compare < 0);
        }
    }
    return compare;
}



bye

Gravatar
Kankrelune
30 May '09 Permalink

q  version_compare() conversion... it's a javascript adaptation of the version_compare() php function found on the Pear php_compat package...

> http://pear.php.net/package/PHP_Compat

function version_compare(version1, version2, operator)
{
    if (!version1)
        return;
    if (!version2)
        return;

    var v1, v2, compare = 0, i = 0, x = 0;
    var standardise = function(v) {
        v = v.replace(/(^\s*)|(\s*$)/g, "").replace(/[-|_|+]/g,'.').replace(/([^0-9\.]+)/g,'.$1.');
        return v.replace(/\.\.*/g,'.').split('.');
    };
    var versions = {
        'dev'   : 0,
        'alpha' : 1,
        'a'     : 1,
        'beta'  : 2,
        'b'     : 2,
        'rc'    : 3,
        '#'     : 4,
        'p'     : 5,
        'pl'    : 5
    };
    
    v1 = standardise(version1);
    v2 = standardise(version2);
    while (!v1[0]) { v1.shift(); }
    while (!v2[0]) { v2.shift(); }
	while (!v1[v1.length-1]) { v1.pop(); }
    while (!v2[v2.length-1]) { v2.pop(); }
    x = (v1.length > v2.length) ? v2.length : v1.length;
    
    for (i = 0; i < x; i++) {
        if (v1[i] == v2[i]) 
            continue;
        
        i1 = v1[i];
        i2 = v2[i];
        
        if (!isNaN(i1) && !isNaN(i2)) {
            compare = (parseInt(i1) < parseInt(i2)) ? -1 : 1;
            break;
        }
        
        if (i1 == '#')
            i1 = '';
                else if (!isNaN(i1))
                    i1 = '#';
        
        if (i2 == '#')
            i2 = '';
                else if (!isNaN(i2))
                    i2 = '#';
        
		i1 = i1.toLowerCase();
		i2 = i2.toLowerCase();
        if (versions[i1] && versions[i2])
           compare = (versions[i1] < versions[i2]) ? -1 : 1;
        else if (versions[i1])
            compare = 1;
        else if (versions[i2])
            compare = -1;
        else
            compare = 0;
		
        break;
    }
    if (compare == 0) {
        if (v2.length > v1.length) {
            if (versions[v2[i].toLowerCase()])
                compare = (versions[v2[i].toLowerCase()] < 4) ? 1 : -1;
                    else
                        compare = -1;
        } 
        else if (v2.length < v1.length) {
            if (versions[v1[i].toLowerCase()])
                compare = (versions[v1[i].toLowerCase()] < 4) ? -1 : 1;
                    else
                        compare = 1;
        }
			
    }
    if (operator) {
        switch (operator) {
            case '>':
            case 'gt':
                return (compare > 0);
            case '>=':
            case 'ge':
                return (compare >= 0);
            case '<=':
            case 'le':
                return (compare <= 0);
            case '==':
            case '=':
            case 'eq':
                return (compare == 0);
            case '<>':
            case '!=':
            case 'ne':
                return (compare != 0);
            case '':
            case '<':
            case 'lt':
            default:
                return (compare < 0);
        }
    }
    return compare;
}



she's work fine...

> http://img20.imageshack.us/my.php?image=testvhw.jpg

Php version credits...


/**
* Replace version_compare()
*
* @category PHP
* @package PHP_Compat
* @license LGPL - http://www.gnu.org/licenses/lgpl.html
* @copyright 2004-2007 Aidan Lister , Arpad Ray
* @link http://php.net/function.version_compare
* @author Philippe Jausions
* @author Aidan Lister
* @version Revision: 1.16
* @since PHP 4.1.0
* @require PHP 4.0.5 (user_error)
*/



cheers

@ tchaOo°

Gravatar
Brett Zamir
2 May '09 Permalink

q  @Theriault, That's awesome to hear. I wasn't looking forward to trying to implement that one. :) I haven't tested your function yet, but wanted to ask if you wouldn't mind testing with http://pastebin.com/m410d37b0 to ensure that we have a somewhat cleaner copy (there was also a debugging alert I commented out, and I changed one use of 'j' to be a new variable 'k' since it seemed like 'k', if on an object, could be a string as we're trying to keep variables to the same type for the sake of declarations/readability (I also wasn't sure about another use of 'j'--line 217 my copy)?, but most of the other changes were for readability, maintainability, and/or early variable "type" declaration--such terse styles may work or save a little space, but can lead to bugs and be more difficult to read/maintain). We're also trying to adhere to http://jslint.com so I'd be most grateful if you could assess whether the remaining gripes of JSLint can be overcome. Also, have you tested with objects? Thank you once again!

Gravatar
Theriault
1 May '09 Permalink

q  I have created working code for the port of array_multisort.

http://pastebin.com/m1d12e821

Gravatar
Khurram Adeeb Noorani
29 Apr '09 Permalink

q  I have better smaller and better solutions for ltrim(), rtrim() and trim()

function ltrim(str)
{
	while(str.charAt(0)==" ")
		str=str.replace(" ","");
	return str;
}
function rtrim(str)
{
	last=str.length-1;
	while(str.charAt(last)==" ")
	{
		str=str.substring(0,last);
		last--;
	}
	return str;
}
function trim(str)
{
	return ltrim(rtrim(str));
}

Gravatar
Kevin van Zonneveld
19 Apr '09 Permalink

q  @ Brett Zamir: Not really PHP-like, but I don't see how it could conflict either. And I do see how this could be really helpful for JS developers. So yes, I'm cool with that.

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: AYHAN BARI*, Nikita Ekshiyan, Nikita Ekshiyan, Petr Pavel, @HalfWinter, Paulo Freitas, Andros Peña Romo, @andorosu, Raimund Szabo, 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 79.6%

php.js on

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



Powered by php.js
Stats