How do I create JavaScript escape sequences in PHP? - php

I'm looking for a way to create valid UTF-16 JavaScript escape sequence characters (including surrogate pairs) from within PHP.
I'm using the code below to get the UTF-32 code points (from a UTF-8 encoded character). This works as JavaScript escape characters (eg. '\u00E1' for 'á') - until you get into the upper ranges where you get surrogate pairs (eg '𝜕' comes out as '\u1D715' but should be '\uD835\uDF15')...
function toOrdinal($chr)
{
if (ord($chr{0}) >= 0 && ord($chr{0}) <= 127)
{
return ord($chr{0});
}
elseif (ord($chr{0}) >= 192 && ord($chr{0}) <= 223)
{
return (ord($chr{0}) - 192) * 64 + (ord($chr{1}) - 128);
}
elseif (ord($chr{0}) >= 224 && ord($chr{0}) <= 239)
{
return (ord($chr{0}) - 224) * 4096 + (ord($chr{1}) - 128) * 64 + (ord($chr{2}) - 128);
}
elseif (ord($chr{0}) >= 240 && ord($chr{0}) <= 247)
{
return (ord($chr{0}) - 240) * 262144 + (ord($chr{1}) - 128) * 4096 + (ord($chr{2}) - 128) * 64 + (ord($chr{3}) - 128);
}
elseif (ord($chr{0}) >= 248 && ord($chr{0}) <= 251)
{
return (ord($chr{0}) - 248) * 16777216 + (ord($chr{1}) - 128) * 262144 + (ord($chr{2}) - 128) * 4096 + (ord($chr{3}) - 128) * 64 + (ord($chr{4}) - 128);
}
elseif (ord($chr{0}) >= 252 && ord($chr{0}) <= 253)
{
return (ord($chr{0}) - 252) * 1073741824 + (ord($chr{1}) - 128) * 16777216 + (ord($chr{2}) - 128) * 262144 + (ord($chr{3}) - 128) * 4096 + (ord($chr{4}) - 128) * 64 + (ord($chr{5}) - 128);
}
}
How do I adapt this code to give me proper UTF-16 code points? Thanks!

How about using iconv (or similarly mb_convert_encoding)?
eg. something like:
$utf16= iconv('UTF-8', 'UTF-16LE', $text);
$codeunits= array();
for ($i= 0; $i<strlen($utf16); $i+= 2) {
$codeunits[]= ord($utf16{$i})+ord($utf16{$i+1})<<8;
}

Here's the final code used (based on the answer from bobince):
$output = '';
$utf16 = iconv(fxCHARSET, 'UTF-16BE', $text);
for ($i= 0; $i < strlen($utf16); $i+= 2)
{
$output.= '\\u'.str_pad(dechex((ord($character{$i}) << 8) + ord($character{$i+1})), 4, '0', STR_PAD_LEFT);
}

Related

Convert 6 array-bytes to int64 using PHP

I'm reverse engineering a javascript script to PHP and there are many functions that convert:
6 array bytes of [224, 221, 199, 147, 195, 47]
and output that to 1632933900000 (which is timestamp, Int64)
Can you help me how to pack/unpack those bytes as above to the final integer using PHP ?
Samples:
[224, 221, 199, 147, 195, 47] gets to 1632933900000
[224, 143, 228, 137, 198, 47]
gets to 1633718700000
ADDITIONAL INFO:
The javascript code is very long (it was obfuscated). I just know for certain that it is placed within 6 bytes.
NEXT UPDATE...
It goes to this function (this.buf is array-bytes):
function u() {
var e = new a(0, 0),
t = 0;
if (!(this.len - this.pos > 4)) {
for (; t < 3; ++t) {
if (this.pos >= this.len) throw s(this);
if (e.lo = (e.lo | (127 & this.buf[this.pos]) << 7 * t) >>> 0, this.buf[this.pos++] < 128) return e
}
return e.lo = (e.lo | (127 & this.buf[this.pos++]) << 7 * t) >>> 0, e
}
for (; t < 4; ++t)
if (e.lo = (e.lo | (127 & this.buf[this.pos]) << 7 * t) >>> 0, this.buf[this.pos++] < 128) return e;
if (e.lo = (e.lo | (127 & this.buf[this.pos]) << 28) >>> 0, e.hi = (e.hi | (127 & this.buf[this.pos]) >> 4) >>> 0, this.buf[this.pos++] < 128) return e;
if (t = 0, this.len - this.pos > 4) {
for (; t < 5; ++t)
if (e.hi = (e.hi | (127 & this.buf[this.pos]) << 7 * t + 3) >>> 0, this.buf[this.pos++] < 128) return e
} else
for (; t < 5; ++t) {
if (this.pos >= this.len) throw s(this);
if (e.hi = (e.hi | (127 & this.buf[this.pos]) << 7 * t + 3) >>> 0, this.buf[this.pos++] < 128) return e
}
throw Error("invalid varint encoding")
}
And then it has [hi and low] numbers and this gets the timestamp:
o.prototype.toNumber = function(e) {
if (!e && this.hi >>> 31) {
var t = 1 + ~this.lo >>> 0,
n = ~this.hi >>> 0;
return t || (n = n + 1 >>> 0), -(t + 4294967296 * n)
}
return this.lo + 4294967296 * this.hi
}
224 221 199 147 195 47 is the decimal representation of E0 DD C7 93 C3 2F ... which is 247243140743983 in decimal. Maybe not the whole dword is the timestamp ...for comparision: 01 7C 32 71 EE E0 or 61 54 98 0C. One can already notice by the first digit, how far off this approach is.
That number in JS might be of type BigInt:
BigInt("0x017C3271EEE0")
But BigInt("0xE0DDC793C32F") still gives 247243140743983.
Just to complete this answer I used following stuff, but I have absolutely no clue what it does :D
<?php
function int64_helper($obj)
{
$e = (object) ['lo' => 0, 'hi' => 0];
if (!($obj->len - $obj->pos > 4)) {
for ($i = 0; $i < 3; $i++) {
if ($obj->pos >= $obj->len) throw new Exception('ERROR RANGE');
$e->lo = rrr($e->lo | ((127 & $obj->buf[$obj->pos]) << (7 * $i)), 0);
if ($obj->buf[$obj->pos++] < 128) return $e;
}
$e->lo = rrr($e->lo | ((127 & $obj->buf[$obj->pos++]) << (7 * $i)), 0);
return $e;
}
for ($i = 0; $i < 4; $i++) {
$e->lo = rrr($e->lo | ((127 & $obj->buf[$obj->pos]) << (7 * $i)), 0);
if ($obj->buf[$obj->pos++] < 128) return $e;
}
$e->lo = rrr(($e->lo | ((127 & $obj->buf[$obj->pos]) << 28)), 0);
$e->hi = rrr(($e->hi | rr((127 & $obj->buf[$obj->pos]), 4)), 0);
if ($obj->buf[$obj->pos++] < 128) {
return $e;
}
if ($obj->len - $obj->pos > 4) {
for ($i = 0; $i < 5; $i++) {
$e->hi = rrr($e->hi | ((127 & $obj->buf[$obj->pos]) << (7 * $i) + 3), 0);
if ($obj->buf[$obj->pos++] < 128) return $e;
}
}
else {
for ($i = 0; $i < 5; $i++) {
if ($obj->pos >= $obj->len) throw new Exception('ERROR RANGE');
$e->hi = rrr($e->hi | ((127 & $obj->buf[$obj->pos]) << (7 * $i) + 3), 0);
if ($obj->buf[$obj->pos++] < 128) return $e;
}
}
throw new Exception("invalid timestamp encoding");
}
/**
* Date time
*/
function int64($obj)
{
$e = int64_helper($obj);
$mst = $e->lo + 4294967296 * $e->hi;
$t = substr($mst, 0, -3); // poslední 3 nuly dávám pryč
$s = date("Y-m-d H:i:s", $t); // prague timezone
return $s;
}
/**
* The >>> javascript operator in php x86_64
* Usage: -1149025787 >>> 0 ---> rrr(-1149025787, 0) === 3145941509
* #return int
*/
function rrr($v, $n)
{
return ($v & 0xFFFFFFFF) >> ($n & 0x1F);
}
/**
* The >> javascript operator in php x86_64
* #return int
*/
function rr($v, $n)
{
return ($v & 0x80000000 ? $v | 0xFFFFFFFF00000000 : $v & 0xFFFFFFFF) >> ($n & 0x1F);
}
/**
* The << javascript operator in php x86_64
* #return int
*/
function ll($v, $n)
{
return ($t = ($v & 0xFFFFFFFF) << ($n & 0x1F)) & 0x80000000 ? $t | 0xFFFFFFFF00000000 : $t & 0xFFFFFFFF;
}

PHP function to convert Hex to HSL (Not HSL to Hex)

Does anyone know how to convert a Hex color to HSL in PHP? I've searched but the functions that I’ve found don’t convert precisely the color.
I think the mistake in the second answer is using integer division rather than fmod() when calculating the hue when red is the maximum colour value $hue = (($green - $blue) / $delta) % 6;
I think the mistake in the first answer is in the saturation calculation -
for me $s = $l > 0.5 ? $diff / (2 - $max - $min) : $diff / ($max + $min); is a bit confusing to unpick
Since usually when I want to convert RGB to HSL I want to adjust the lightness value to make a lighter or darker version of the same colour, I have built that into the function below by adding an optional $ladj percent value.
The $hex parameter can be either a hex string (with or without the '#') or an array of RGB values (between 0 and 255)
The return value is an HSL string ready to drop straight in to a CSS colour. ie the values are from 0 to 359 for hue and 0 to 100% for saturation and lightness.
I think this works correctly (based on https://gist.github.com/brandonheyer/5254516)
function hex2hsl($RGB, $ladj = 0) {
//have we got an RGB array or a string of hex RGB values (assume it is valid!)
if (!is_array($RGB)) {
$hexstr = ltrim($RGB, '#');
if (strlen($hexstr) == 3) {
$hexstr = $hexstr[0] . $hexstr[0] . $hexstr[1] . $hexstr[1] . $hexstr[2] . $hexstr[2];
}
$R = hexdec($hexstr[0] . $hexstr[1]);
$G = hexdec($hexstr[2] . $hexstr[3]);
$B = hexdec($hexstr[4] . $hexstr[5]);
$RGB = array($R,$G,$B);
}
// scale the RGB values to 0 to 1 (percentages)
$r = $RGB[0]/255;
$g = $RGB[1]/255;
$b = $RGB[2]/255;
$max = max( $r, $g, $b );
$min = min( $r, $g, $b );
// lightness calculation. 0 to 1 value, scale to 0 to 100% at end
$l = ( $max + $min ) / 2;
// saturation calculation. Also 0 to 1, scale to percent at end.
$d = $max - $min;
if( $d == 0 ){
// achromatic (grey) so hue and saturation both zero
$h = $s = 0;
} else {
$s = $d / ( 1 - abs( (2 * $l) - 1 ) );
// hue (if not grey) This is being calculated directly in degrees (0 to 360)
switch( $max ){
case $r:
$h = 60 * fmod( ( ( $g - $b ) / $d ), 6 );
if ($b > $g) { //will have given a negative value for $h
$h += 360;
}
break;
case $g:
$h = 60 * ( ( $b - $r ) / $d + 2 );
break;
case $b:
$h = 60 * ( ( $r - $g ) / $d + 4 );
break;
} //end switch
} //end else
// make any lightness adjustment required
if ($ladj > 0) {
$l += (1 - $l) * $ladj/100;
} elseif ($ladj < 0) {
$l += $l * $ladj/100;
}
//put the values in an array and scale the saturation and lightness to be percentages
$hsl = array( round( $h), round( $s*100), round( $l*100) );
//we could return that, but lets build a CSS compatible string and return that instead
$hslstr = 'hsl('.$hsl[0].','.$hsl[1].'%,'.$hsl[2].'%)';
return $hslstr;
}
In real life I would break out the hex string to RGB array conversion and the percentage adjustment into separate functions, but have included them here for completeness.
You could also use the percent adjustment to shift the hue or saturation once you've got the colour in HSL format.
function hexToHsl($hex) {
$hex = array($hex[0].$hex[1], $hex[2].$hex[3], $hex[4].$hex[5]);
$rgb = array_map(function($part) {
return hexdec($part) / 255;
}, $hex);
$max = max($rgb);
$min = min($rgb);
$l = ($max + $min) / 2;
if ($max == $min) {
$h = $s = 0;
} else {
$diff = $max - $min;
$s = $l > 0.5 ? $diff / (2 - $max - $min) : $diff / ($max + $min);
switch($max) {
case $rgb[0]:
$h = ($rgb[1] - $rgb[2]) / $diff + ($rgb[1] < $rgb[2] ? 6 : 0);
break;
case $rgb[1]:
$h = ($rgb[2] - $rgb[0]) / $diff + 2;
break;
case $rgb[2]:
$h = ($rgb[0] - $rgb[1]) / $diff + 4;
break;
}
$h /= 6;
}
return array($h, $s, $l);
}
Rewritten (and adjusted a bit) from javascript from https://css-tricks.com/converting-color-spaces-in-javascript/
<?php
function hexToHsl($hex)
{
$red = hexdec(substr($hex, 0, 2)) / 255;
$green = hexdec(substr($hex, 2, 2)) / 255;
$blue = hexdec(substr($hex, 4, 2)) / 255;
$cmin = min($red, $green, $blue);
$cmax = max($red, $green, $blue);
$delta = $cmax - $cmin;
if ($delta === 0) {
$hue = 0;
} elseif ($cmax === $red) {
$hue = (($green - $blue) / $delta) % 6;
} elseif ($cmax === $green) {
$hue = ($blue - $red) / $delta + 2;
} else {
$hue = ($red - $green) / $delta + 4;
}
$hue = round($hue * 60);
if ($hue < 0) {
$hue += 360;
}
$lightness = (($cmax + $cmin) / 2) * 100;
$saturation = $delta === 0 ? 0 : ($delta / (1 - abs(2 * $lightness - 1))) * 100;
if ($saturation < 0) {
$saturation += 100;
}
$lightness = round($lightness);
$saturation = round($saturation);
return "hsl(${hue}, ${saturation}%, ${lightness}%)";
}
Example:
<?php
echo hexToHsl('fbffe0'); // outputs 'hsl(68, 100%, 94%)'

How to calculate a certain color based on another color?

For example I have a blue color:
#049cd9 or rgba(4, 156, 218)
How can I calculate the correspondent color, which in this case it would be a dark blue color:
#004ea0 or rgba(0, 78, 160)
?
Normally I don't know the 2nd color (that I want to find out), so I want to find a way to get the darker color based on the first color.
Is there a formula or something that I can generate by substracting the two colors somehow?
So I've found HEX to HSL and HSL to HEX functions:
function hex_to_hue($hexcode)
{
$redhex = substr($hexcode,0,2);
$greenhex = substr($hexcode,2,2);
$bluehex = substr($hexcode,4,2);
// $var_r, $var_g and $var_b are the three decimal fractions to be input to our RGB-to-HSL conversion routine
$var_r = (hexdec($redhex)) / 255;
$var_g = (hexdec($greenhex)) / 255;
$var_b = (hexdec($bluehex)) / 255;
// Input is $var_r, $var_g and $var_b from above
// Output is HSL equivalent as $h, $s and $l — these are again expressed as fractions of 1, like the input values
$var_min = min($var_r,$var_g,$var_b);
$var_max = max($var_r,$var_g,$var_b);
$del_max = $var_max - $var_min;
$l = ($var_max + $var_min) / 2;
if ($del_max == 0) {
$h = 0;
$s = 0;
} else {
if ($l < 0.5) {
$s = $del_max / ($var_max + $var_min);
} else {
$s = $del_max / (2 - $var_max - $var_min);
}
;
$del_r = ((($var_max - $var_r) / 6) + ($del_max / 2)) / $del_max;
$del_g = ((($var_max - $var_g) / 6) + ($del_max / 2)) / $del_max;
$del_b = ((($var_max - $var_b) / 6) + ($del_max / 2)) / $del_max;
if ($var_r == $var_max) {
$h = $del_b - $del_g;
} else if ($var_g == $var_max) {
$h = (1 / 3) + $del_r - $del_b;
} else if ($var_b == $var_max) {
$h = (2 / 3) + $del_g - $del_r;
}
;
if ($h < 0) {
$h += 1;
}
;
if ($h > 1) {
$h -= 1;
}
;
}
;
return array($h, $s, $l);
/*
// Calculate the opposite hue, $h2
$h2 = $h + 0.5;
if ($h2 > 1)
{
$h2 -= 1;
};
return array($h2, $s, $l);
*/
}
function hue_to_hex($hue = array())
{
function hue_2_rgb($v1,$v2,$vh)
{
if ($vh < 0) {
$vh += 1;
}
;
if ($vh > 1) {
$vh -= 1;
}
;
if ((6 * $vh) < 1) {
return($v1 + ($v2 - $v1) * 6 * $vh);
}
;
if ((2 * $vh) < 1) {
return($v2);
}
;
if ((3 * $vh) < 2) {
return($v1 + ($v2 - $v1) * ((2 / 3 - $vh) * 6));
}
;
return($v1);
}
;
list($h2, $s, $l) = $hue;
// Input is HSL value of complementary colour, held in $h2, $s, $l as fractions of 1
// Output is RGB in normal 255 255 255 format, held in $r, $g, $b
// Hue is converted using function hue_2_rgb, shown at the end of this code
if ($s == 0) {
$r = $l * 255;
$g = $l * 255;
$b = $l * 255;
} else {
if ($l < 0.5) {
$var_2 = $l * (1 + $s);
} else {
$var_2 = ($l + $s) - ($s * $l);
}
;
$var_1 = 2 * $l - $var_2;
$r = 255 * hue_2_rgb($var_1,$var_2,$h2 + (1 / 3));
$g = 255 * hue_2_rgb($var_1,$var_2,$h2);
$b = 255 * hue_2_rgb($var_1,$var_2,$h2 - (1 / 3));
}
;
$rhex = sprintf("%02X",round($r));
$ghex = sprintf("%02X",round($g));
$bhex = sprintf("%02X",round($b));
return $rhex.$ghex.$bhex;
}
They work because I tested them by converting a color back and forth.
But I don't know how can I change the Hue and Luminosity properties just like in Photoshop?
The dark color would be H +13 and L -28.
And the hex_to_hsl function above returns float values between 0 and 1...
There are formulas that convert an RGB color to HSV (Hue, Saturation and Value). From the HSV you can change any of the HSV components and then convert back to RGB. I've found stuff online and done this before. Let me know if you want more details on the algorithms, I can dig them up for you if you want.
#XXXXXX represent hexa decimal number in colors for RED, GREEN and BLUE, each two characters from left to right if you increase the number it will get light, if decrease the number, it will be darker.
You need to convert the RGB value to HSL or HSV and then you can decrease the L (luma) or V (value) component as you wish and then convert back to RGB.
see this answer for example code:
RGB to HSV in PHP
The easiest way to tinker with how colours are perceived (ie, lighter, darker, brighter, duller, etc) is to convert it to HSL. There are plenty of resources online for converting RGB to HSL and back again in PHP and JavaScript. Google will find you as many implementations as you want. Then to decrease the lightness, reduce the L value (multiply by 0.75 or similar) and convert back to RGB.
function hex_to_hue($hexcode, $percent) {
$redhex = substr($hexcode, 0, 2);
$greenhex = substr($hexcode, 2, 2);
$bluehex = substr($hexcode, 4, 2);
// $var_r, $var_g and $var_b are the three decimal fractions to be input to our RGB-to-HSL conversion routine
$var_r = (hexdec($redhex)) / 255;
$var_g = (hexdec($greenhex)) / 255;
$var_b = (hexdec($bluehex)) / 255;
// Input is $var_r, $var_g and $var_b from above
// Output is HSL equivalent as $h, $s and $l — these are again expressed as fractions of 1, like the input values
$var_min = min($var_r, $var_g, $var_b);
$var_max = max($var_r, $var_g, $var_b);
$del_max = $var_max - $var_min;
$l = ($var_max + $var_min) / 2;
if ($del_max == 0) {
$h = 0;
$s = 0;
} else {
if ($l < 0.5) {
$s = $del_max / ($var_max + $var_min);
} else {
$s = $del_max / (2 - $var_max - $var_min);
}
;
$del_r = ((($var_max - $var_r) / 6) + ($del_max / 2)) / $del_max;
$del_g = ((($var_max - $var_g) / 6) + ($del_max / 2)) / $del_max;
$del_b = ((($var_max - $var_b) / 6) + ($del_max / 2)) / $del_max;
if ($var_r == $var_max) {
$h = $del_b - $del_g;
} else if ($var_g == $var_max) {
$h = (1 / 3) + $del_r - $del_b;
} else if ($var_b == $var_max) {
$h = (2 / 3) + $del_g - $del_r;
}
;
if ($h < 0) {
$h += 1;
}
;
if ($h > 1) {
$h -= 1;
}
;
}
;
//return array($h, $s, $l);
// Calculate the opposite hue, $h2
$h2 = $h + $percent;
if ($h2 > 1) {
$h2 -= 1;
}
// Calculate the opposite hue, $s2
$s2 = $s + $percent;
if ($s2 > 1) {
$s2 -= 1;
}
// Calculate the opposite hue, $s2
$l2 = $l + $percent;
if ($l2 > 1) {
$l2 -= 1;
}
return array($h2, $s2, $l2);
}

How do I make a lighter version of a colour using PHP?

Hello fellow earthlings. A quesion about RGB color and its usefulness in a simple tiny php code:
Imagine I have variable $colorA containning a valid six char color. say B1B100, a greenish natural color. Now If I would like to make a new color from that, which is, say, ten steps lighter thatn that original color, roughly.
$colorA = B1B100 // original color
php code with little color engine lightening stuff up goes here
$colorB = ?????? // original color lightened up
Is there a php ready function that KNOWS rgb colors something like
php function RGB ( input color, what to do, output color)
Where what to do could be +/- 255 values of brightness etc etc.
Is something like this already possible or am I day dreaming?
rgb-hsl($colorA, +10, $colorB);
If this does not exist, what would be the shortest code for doing this? Suggestions, code or ideas are all answers to me. Thanks.
This SO question has a full-blown PHP script that can convert a RGB to a HSL colour, and increase its H component of a HSL colour - it should be trivial to change to increase L instead.
In general if you want a lighter shade of a particular colour, the most accurate process is to convert from RGB to HSL (or HSV), change the 'L' (or 'V') value which represents lightness, and then convert back to RGB.
This will preserve the "hue", which represents where the colour sits on the spectrum, but change the "tint" (if lightening) or "shade" (if darkening) of that colour.
See http://en.wikipedia.org/wiki/HSL_and_HSV for more information.
On this website: http://www.sitepoint.com/forums/showthread.php?t=586223 they are talking about this code which is originally made by opensource Drupal. Seems to work fine in PHP!?
Now, how do I now indermingle myself with this code and change the lightness of an HSL value, before its outputted as RGB again?
<?php
### RGB >> HSL
function _color_rgb2hsl($rgb) {
$r = $rgb[0]; $g = $rgb[1]; $b = $rgb[2];
$min = min($r, min($g, $b)); $max = max($r, max($g, $b));
$delta = $max - $min; $l = ($min + $max) / 2; $s = 0;
if ($l > 0 && $l < 1) {
$s = $delta / ($l < 0.5 ? (2 * $l) : (2 - 2 * $l));
}
$h = 0;
if ($delta > 0) {
if ($max == $r && $max != $g) $h += ($g - $b) / $delta;
if ($max == $g && $max != $b) $h += (2 + ($b - $r) / $delta);
if ($max == $b && $max != $r) $h += (4 + ($r - $g) / $delta);
$h /= 6;
} return array($h, $s, $l);
}
### HSL >> RGB
function _color_hsl2rgb($hsl) {
$h = $hsl[0]; $s = $hsl[1]; $l = $hsl[2];
$m2 = ($l <= 0.5) ? $l * ($s + 1) : $l + $s - $l*$s;
$m1 = $l * 2 - $m2;
return array(_color_hue2rgb($m1, $m2, $h + 0.33333),
_color_hue2rgb($m1, $m2, $h),
_color_hue2rgb($m1, $m2, $h - 0.33333));
}
### Helper function for _color_hsl2rgb().
function _color_hue2rgb($m1, $m2, $h) {
$h = ($h < 0) ? $h + 1 : (($h > 1) ? $h - 1 : $h);
if ($h * 6 < 1) return $m1 + ($m2 - $m1) * $h * 6;
if ($h * 2 < 1) return $m2;
if ($h * 3 < 2) return $m1 + ($m2 - $m1) * (0.66666 - $h) * 6;
return $m1;
}
### Convert a hex color into an RGB triplet.
function _color_unpack($hex, $normalize = false) {
if (strlen($hex) == 4) {
$hex = $hex[1] . $hex[1] . $hex[2] . $hex[2] . $hex[3] . $hex[3];
} $c = hexdec($hex);
for ($i = 16; $i >= 0; $i -= 8) {
$out[] = (($c >> $i) & 0xFF) / ($normalize ? 255 : 1);
} return $out;
}
### Convert an RGB triplet to a hex color.
function _color_pack($rgb, $normalize = false) {
foreach ($rgb as $k => $v) {
$out |= (($v * ($normalize ? 255 : 1)) << (16 - $k * 8));
}return '#'. str_pad(dechex($out), 6, 0, STR_PAD_LEFT);
}
/* $testrgb = array(0.2,0.75,0.4); //RGB to start with
print_r($testrgb); */
print "Hex: ";
$testhex = "#b7b700";
print $testhex;
$testhex2rgb = _color_unpack($testhex,true);
print "<br />RGB: ";
var_dump($testhex2rgb);
print "<br />HSL color module: ";
$testrgb2hsl = _color_rgb2hsl($testhex2rgb); //Converteren naar HSL
var_dump($testrgb2hsl);
print "<br />RGB: ";
$testhsl2rgb = _color_hsl2rgb($testrgb2hsl); // En weer terug naar RGB
var_dump($testhsl2rgb);
print "<br />Hex: ";
$testrgb2hex = _color_pack($testhsl2rgb,true);
var_dump($testrgb2hex);
?>
PHP does have a couple image manipulation libraries. Either GD or Imagemagick
EDIT: I jumped the gun, these libraries do not have direct PHP color manipulation functions - I honestly assumed they did of a sort after seeing a lot of the things they can do with images via PHP. They do accomplish a lot of cool things. Here's one guy's example.

Recreate Excel RATE function using Newton's Method

I'm working on converting a mortgage calculator in PHP, but I don't necessarily need a PHP solution. I'm looking for the logic needed to replicate the Excel RATE function. I've found a solution which uses bisection, and if worse comes to worse, I use that.
I know someone out there in the interwebs world has knowledge of such a function, so I'd love to have an easy answer instead of creating a solution from scratch.
References:
http://office.microsoft.com/en-us/excel-help/rate-HP005209232.aspx
http://en.wikipedia.org/wiki/Newton%27s_method
Thanks
Implementation of the MS Excel RATE() function using the secant method (a finite difference approximation of Newton's method) taken from PHPExcel:
define('FINANCIAL_MAX_ITERATIONS', 128);
define('FINANCIAL_PRECISION', 1.0e-08);
function RATE($nper, $pmt, $pv, $fv = 0.0, $type = 0, $guess = 0.1) {
$rate = $guess;
if (abs($rate) < FINANCIAL_PRECISION) {
$y = $pv * (1 + $nper * $rate) + $pmt * (1 + $rate * $type) * $nper + $fv;
} else {
$f = exp($nper * log(1 + $rate));
$y = $pv * $f + $pmt * (1 / $rate + $type) * ($f - 1) + $fv;
}
$y0 = $pv + $pmt * $nper + $fv;
$y1 = $pv * $f + $pmt * (1 / $rate + $type) * ($f - 1) + $fv;
// find root by secant method
$i = $x0 = 0.0;
$x1 = $rate;
while ((abs($y0 - $y1) > FINANCIAL_PRECISION) && ($i < FINANCIAL_MAX_ITERATIONS)) {
$rate = ($y1 * $x0 - $y0 * $x1) / ($y1 - $y0);
$x0 = $x1;
$x1 = $rate;
if (abs($rate) < FINANCIAL_PRECISION) {
$y = $pv * (1 + $nper * $rate) + $pmt * (1 + $rate * $type) * $nper + $fv;
} else {
$f = exp($nper * log(1 + $rate));
$y = $pv * $f + $pmt * (1 / $rate + $type) * ($f - 1) + $fv;
}
$y0 = $y1;
$y1 = $y;
++$i;
}
return $rate;
} // function RATE()
I tried to use the code above, but the results simply aren´t the same as Excel (or Google Spreadsheet).
I dont know if you need to implement this function yet, but in any case, I looked at how this algorithm was built and even though I was not able to access the excel source code (or the google worksheet) I found that this is not a simple calculation. About this math, more can be read here:
https://brownmath.com/bsci/loan.htm#Eq8
The function, in PHP, may be something like this:
function rate($nprest, $vlrparc, $vp, $guess = 0.25) {
$maxit = 100;
$precision = 14;
$guess = round($guess,$precision);
for ($i=0 ; $i<$maxit ; $i++) {
$divdnd = $vlrparc - ( $vlrparc * (pow(1 + $guess , -$nprest)) ) - ($vp * $guess);
$divisor = $nprest * $vlrparc * pow(1 + $guess , (-$nprest - 1)) - $vp;
$newguess = $guess - ( $divdnd / $divisor );
$newguess = round($newguess, $precision);
if ($newguess == $guess) {
return $newguess;
} else {
$guess = $newguess;
}
}
return null;
}
For Laravel use the same function but you remove define
define('FINANCIAL_MAX_ITERATIONS', 128);
define('FINANCIAL_PRECISION', 1.0e-08);
and financial_max_iterations = 20; -> same excel
The code is:
function RATE($nper, $pmt, $pv, $fv = 0.0, $type = 0, $guess = 0.1) {
$financial_max_iterations = 20;
$financial_precision = 0.00000008;
$rate = $guess;
if (abs($rate) < $financial_precision) {
$y = $pv * (1 + $nper * $rate) + $pmt * (1 + $rate * $type) * $nper + $fv;
} else {
$f = exp($nper * log(1 + $rate));
$y = $pv * $f + $pmt * (1 / $rate + $type) * ($f - 1) + $fv;
}
$y0 = $pv + $pmt * $nper + $fv;
$y1 = $pv * $f + $pmt * (1 / $rate + $type) * ($f - 1) + $fv;
// find root by secant method
$i = $x0 = 0.0;
$x1 = $rate;
while ((abs($y0 - $y1) > $financial_precision) && ($i < $financial_max_iterations)) {
$rate = ($y1 * $x0 - $y0 * $x1) / ($y1 - $y0);
$x0 = $x1;
$x1 = $rate;
if (abs($rate) < $financial_precision) {
$y = $pv * (1 + $nper * $rate) + $pmt * (1 + $rate * $type) * $nper + $fv;
} else {
$f = exp($nper * log(1 + $rate));
$y = $pv * $f + $pmt * (1 / $rate + $type) * ($f - 1) + $fv;
}
$y0 = $y1;
$y1 = $y;
++$i;
}
return $rate;
}
it worked for me
TL;DR: Here's a SQL Server version. It doesn't work for some values, and the PHP code above will probably fail for the same values.
LONG ANSWER: I needed a RATE function for SQL Server. Using the PHPExcel answer above, and using https://charlottecredittechnology.blogspot.com/2013/05/sql-2008-excel-like-rate-function-part.html I wrote a SQL Server scalar function:
ALTER function [dbo].[Rate](
#nper integer, #pmt float, #pv float, #fv float, #type bit = 0, #guess float = 0.1
) returns numeric(38,10) as
/*
Calculate the effective interest rate of a sequence of regular payments.
*/
begin
declare #returns numeric(38,10) = 0;
if #type is null set #type = 0;
declare #i integer;
declare #rate float = #guess;
declare #FINANCIAL_MAX_ITERATIONS integer = 100;
declare #FINANCIAL_PRECISION float = 0.0000001;
declare #y float, #y0 float, #y1 float, #f float, #x0 float, #x1 float;
set #rate = #guess;
if Abs(#rate) < #FINANCIAL_PRECISION
begin
set #f = 0;
set #y = #pv * (1+#nper*#rate) + #pmt * (1+#rate*#type) * #nper + #fv;
end
else
begin
set #f = Exp(#nper * Log(1+#rate));
set #y = #pv * #f + #pmt * (1/#rate + #type) * (#f-1) + #fv;
end;
set #y0 = #pv + #pmt * #nper + #fv;
set #y1 = #pv * #f + #pmt * (1/#rate + #type) * (#f-1) + #fv;
-- Newton secant method.
set #i = 0;
set #x0 = 0;
set #x1 = #rate;
while Abs(#y0-#y1) > #FINANCIAL_PRECISION and #i < #FINANCIAL_MAX_ITERATIONS
begin
set #rate = (#y1 * #x0 - #y0 * #x1) / (#y1-#y0);
set #x0 = #x1;
set #x1 = #rate;
if Abs(#rate) < #FINANCIAL_PRECISION
begin
set #y = #pv * (1+#nper*#rate) + #pmt * (1+#rate*#type) * #nper + #fv;
end
else
begin
set #f = Exp(#nper * Log(1+#rate));
set #y = #pv * #f + #pmt * (1/#rate + #type) * (#f-1) + #fv;
end;
set #y0 = #y1;
set #y1 = #y;
set #i = #i + 1;
end;
return Convert(numeric(38,10), #rate);
end;
Unfortunately it does not always work. Here's the results of some tests I put together and checked using Excel:
-- (1) OK
select dbo.RATE(4*12, -200, 8000, 0, default, default) * 12 -- SQL formula
0.0924 (9.24%) -- SQL result
=RATE(4*12, -200, 8000, 0) * 12 -- Excel formula
9.24% -- Excel result
-- (2) OK
select dbo.RATE(12, -1000, 12000, 0, default, default) * 12 -- SQL formula
0 (0%) -- SQL result
=RATE(12, -1000, 12000, 0) * 12 -- Excel formula
0% -- Excel result
-- (3) OK
select dbo.RATE(30, -400, 4000, 0, 1, default) -- SQL formula
0.10496 (10.496%) -- SQL result
=RATE(30, -400, 4000, 0, 1) -- Excel formula
10.4964% -- Excel result
-- (4) OK
select dbo.RATE(120, 28.1, -2400, 0, default, default) -- SQL formula
0.0059905810 (0.599%) -- SQL result
=RATE(120, 28.1, -2400, 0) -- Excel formula
0.5991% -- Excel result
-- (5) OK
select dbo.RATE(10, -1000, 10000, -10000, default, default) -- SQL formula
0.1 (10%) -- SQL result
=RATE(10, -1000, 10000, -10000) -- Excel formula
10% -- Excel result
-- (6) WRONG ANSWER (unless you set #guess to 0.01)
select dbo.RATE(475, -1022.93, 272779.21, 0, default, default) -- SQL formula
0 -- SQL result
=RATE(475, -1022.93, 272779.21, 0, 0) -- Excel formula
0.2716% -- Excel result
-- (7) ERROR
select dbo.RATE(252, -29002.85, 2500000, 0, default, default) -- SQL formula
invalid floating point operation -- SQL result
=RATE(252, -29002.85, 2500000, 0) -- Excel formula
1.0833% -- Excel result
-- (8) OK
select dbo.RATE(24, -46.14, 1000, 0, default, default) -- SQL formula
0.0083244385 (0.83244%) -- SQL result
=RATE(24, -46.14, 1000, 0) -- Excel formula
0.8324% -- Excel result
Tests (7) and (8) were taken from RATE Function from EXCEL in Swift providing different results and look for the answer using the Newton-Raphson method.

Categories