php warning -Invalid argument supplied for foreach() - php

i installed a project edusec school management system which work on php mysql yii framework.but when we copy it root directory and run index.php on local server it give following error ? what i do ??please help me?
PHP warning
Invalid argument supplied for foreach()
C:\xampp\htdocs\yiitest\protected\yii\framework\collections\CMap.php(288)
276 * #param array $b array to be merged from. You can specifiy additional
277 * arrays via third argument, fourth argument etc.
278 * #return array the merged array (the original arrays are not changed.)
279 * #see mergeWith
280 */
281 public static function mergeArray($a,$b)
282 {
283 $args=func_get_args();
284 $res=array_shift($args);
285 while(!empty($args))
286 {
287 $next=array_shift($args);
288 foreach($next as $k => $v)
289 {
290 if(is_integer($k))
291 isset($res[$k]) ? $res[]=$v : $res[$k]=$v;
292 else if(is_array($v) && isset($res[$k]) && is_array($res[$k]))
293 $res[$k]=self::mergeArray($res[$k],$v);
294 else
295 $res[$k]=$v;
296 }
297 }
298 return $res;
299 }
300
Stack Trace
#0
– C:\xampp\htdocs\yiitest\protected\yii\framework\base\CModule.php(468): CMap::mergeArray(array("class" => "CDbConnection"), 1)
463 foreach($components as $id=>$component)
464 {
465 if($component instanceof IApplicationComponent)
466 $this->setComponent($id,$component);
467 else if(isset($this->_componentConfig[$id]) && $merge)
468 $this->_componentConfig[$id]=CMap::mergeArray($this->_componentConfig[$id],$component);
469 else
470 $this->_componentConfig[$id]=$component;
471 }
472 }
473
#1
+ C:\xampp\htdocs\yiitest\protected\yii\framework\base\CComponent.php(153): CModule->setComponents(array("user" => array("allowAutoLogin" => true, "class" => "RWebUser"), "phpThumb" => array("class" => "ext.EPhpThumb.EPhpThumb"), "authManager" => array("class" => "RDbAuthManager"), "urlManager" => array("urlFormat" => "path", "rules" => array("<controller:\w+>/<id:\d+>" => "<controller>/view", "<controller:\w+>/<action:\w+>/<id:\d+>" => "<controller>/<action>", "<controller:\w+>/<action:\w+>" => "<controller>/<action>")), ...))
#2
+ C:\xampp\htdocs\yiitest\protected\yii\framework\base\CModule.php(483): CComponent->__set("components", array("user" => array("allowAutoLogin" => true, "class" => "RWebUser"), "phpThumb" => array("class" => "ext.EPhpThumb.EPhpThumb"), "authManager" => array("class" => "RDbAuthManager"), "urlManager" => array("urlFormat" => "path", "rules" => array("<controller:\w+>/<id:\d+>" => "<controller>/view", "<controller:\w+>/<action:\w+>/<id:\d+>" => "<controller>/<action>", "<controller:\w+>/<action:\w+>" => "<controller>/<action>")), ...))
#3
+ C:\xampp\htdocs\yiitest\protected\yii\framework\base\CApplication.php(144): CModule->configure(array("name" => "College Management System", "preload" => array("log"), "import" => array("application.models.*", "application.extensions.jtogglecolumn.*", "application.extensions.AjaxList.AjaxList", "application.components.*", ...), "modules" => array("gii" => array("class" => "system.gii.GiiModule", "password" => "secure", "generatorPaths" => array("ext.gii-extended"), "ipFilters" => array("127.0.0.1", "::1", "192.168.0.163")), 0 => "notification", 1 => "webservice", "rights" => array("install" => false, "superuserName" => "SuperAdmin", "authenticatedName" => "Authenticated", "userIdColumn" => "user_id", ...), ...), ...))
#4
+ C:\xampp\htdocs\yiitest\protected\yii\framework\YiiBase.php(127): CApplication->__construct("C:\xampp\htdocs\yiitest/protected/config/main.php")
#5
+ C:\xampp\htdocs\yiitest\protected\yii\framework\YiiBase.php(100): YiiBase::createApplication("CWebApplication", "C:\xampp\htdocs\yiitest/protected/config/main.php")
#6
– C:\xampp\htdocs\yiitest\index.php(18): YiiBase::createWebApplication("C:\xampp\htdocs\yiitest/protected/config/main.php")
13
14 // specify how many levels of call stack should be shown in each log message
15 defined('YII_TRACE_LEVEL') or define('YII_TRACE_LEVEL',3);
16
17 require_once($yii);
18 Yii::createWebApplication($config)->run();
19 ?>
20

The function array_shift() at line 287 has returned null, so $next is not an array.
And of course foreach() requires an array.

Validate the value before passing into the loop. This will catch when the array is empty.
$next=array_shift($args);
if ($next != null)
{
foreach($next as $k => $v)
{
// do things here
}
}

Related

Invalid parameter number in eloquent

I've got this query :
use Illuminate\Database\Capsule\Manager as DB;
$arr = [/* Array values here */];
$in = str_repeat('?,', count($arr) - 1) . '?';
$str = "SELECT ... FROM ... WHERE ... AND ... IN ($in)";
$select_categories = DB::select($str, $arr);
Now I'm getting the error Uncaught PDOException: SQLSTATE[HY093]: Invalid parameter number, this is the stack trace :
/var/www/vendor/illuminate/database/Connection.php:330 Stack trace: #0 /var/www/vendor/illuminate/database/Connection.php(330): PDOStatement->execute() #1 /var/www/vendor/illuminate/database/Connection.php(657): Illuminate\Database\Connection->Illuminate\Database{closure}('SELECT categori...', Array) #2 /var/www/vendor/illuminate/database/Connection.php(624): Illuminate\Database\Connection->runQueryCallback('SELECT categori...', Array, Object(Closure)) #3 /var/www/vendor/illuminate/database/Connection.php(333): Illuminate\Database\Connection->run('SELECT name...', Array, Object(Closure)) #4 /var/www/vendor/illuminate/database/Capsule/Manager.php(199): Illuminate\Database\Connection->select('SELECT name...', Array) #5 /var/www/categ.class.php(81): Illuminate\Database\Capsule\Manager::__callStatic('select', Array) #6 /var/www/categ.class.php(123): Site\Naviga in /var/www/vendor/illuminate/database/Connection.php on line 664
I don't get why this is happening. I'm trying to echo the variables $str and $arr to try and see if the number of ? matches the count of the array and indeed it does. So I can't see why is that error being generated. Any idea?
In the stack there are 3 arguments run('SELECT name...', Array, Object(Closure)), maybe this is causing the issue as it thinks there is a third parametre which there isn't? Or something like that?
EDIT :
$str contains : "?,?,?,?,?,?"
$arr contains : [94, 91, 97, 92, 96, 90]
Result of dd($str, $arr); :
"SELECT ... FROM ... WHERE ... IN (?,?,?,?,?,?,?,?,?,?,?,?,?,?) ORDER BY pro.sort_order"
array:14 [
0 => "56"
1 => "163"
4 => "64"
6 => "53"
7 => "52"
10 => "55"
12 => "59"
13 => "57"
28 => "157"
43 => "60"
49 => "133"
68 => "287"
101 => "54"
109 => "278"
]
The solution is to use array_values($arr) instead of $arr in the select() method:
$select_categories = DB::select($str, array_values($arr));
$in has 14 ? and $arr has 14 elements. The reason why it does not work is because indexes of $arr are not from 0 to 13 but from 0 to 109. Since indexes are integer and not string, all of them from 0 to 109 exist even if some are null, so the size of $arr is 110.
The effect of using array_values() on $arr:
array:14 [
0 => "56"
1 => "163"
2 => "64"
3 => "53"
4 => "52"
5 => "55"
6 => "59"
7 => "57"
8 => "157"
9 => "60"
10 => "133"
11 => "287"
12 => "54"
13 => "278"
]

PHP sort seems to malfunction

### Result of sort
sort($keys_arranged, SORT_NUMERIC);
var_dump($keys_arranged);
{ ...
[51]=> float(11.903327742296)
[52]=> int(5)
[53]=> float(13.165002546636)
[54]=> float(14.478273306964)
[55]=> float(4.6264742674547)
[56]=> float(13.290508819344)
[57]=> float(15.686809055276) }
### Result or rsort
rsort($keys_arranged, SORT_NUMERIC);
var_dump($keys_arranged);
{
[0]=> float(15.686809055276)
[1]=> float(14.478273306964)
[2]=> float(13.290508819344)
[3]=> float(13.165002546636)
[4]=> float(11.903327742296)
[5]=> int(5)
[6]=> float(4.6264742674547)
... }
echo var_export($keys_arranged);
array ( 0 => 3.142678516658294, 1 => 1.0, 2 => 1.0, 3 => 14.478273306963985, 4 => 13.165002546635966, 5 => 1.0, 6 => 1.0005037081114851, 7 => 1.0, 8 => 4.6264742674547001, 9 => 15.686809055275578, 10 => 1.0, 11 => 11.903327742295504, 12 => 13.29050881934397, 13 => 1.0, 14 => 1.0, 15 => 3.5421134937189365, 16 => 1.0, 17 => 0.010999999999999999, 18 => 3.2999566681750605, 19 => 5, 20 => 1.2282984802843129, 21 => 1.0, 22 => 2.9748253120971184, 23 => 0.44855992975075798, 24 => 0.99999999999999989, 25 => 3.8350475954623371, 26 => 1.0625975061426283, 27 => 1.0000072792091179, 28 => 0.99999987785487132, 29 => 1, 30 => 0.0, 31 => 1.0, 32 => 1.0, 33 => 1.0, 34 => 0.0, 35 => 1.0972568578553616, 36 => 1.0, 37 => 1.4077661823957415, 38 => 1.0, 39 => 0.0, 40 => 3.6038030347555705, 41 => 1.0, 42 => 1.0, 43 => 1.0636876768842174, 44 => 1.0, 45 => NAN, 46 => 1.0, 47 => NAN, 48 => NAN, 49 => NAN, 50 => NAN, 51 => 1.0, 52 => 1.0, 53 => NAN, 54 => 0.99958680716631509, 55 => 1.0, 56 => NAN, 57 => 1.0, )
I got some incorrect result from array_multisort. It has 8 different keys and all the keys but this key(say A) works fine.
To figure out why that happened, I played with A in the array. And I could see that not only in the function of array_multisort, but also in 'sort' function, an incorrect result prompted as well.
As you can see the result of rsort seems okay, the result of sort works strangely when it comes to
13.16 < 14.47 < 4.62 < 13.29 < 15.68
Does anyone know why this occurred?
// Data in readible format
array (
0 => 3.142678516658294,
1 => 1.0,
2 => 1.0,
3 => 14.478273306963985,
4 => 13.165002546635966,
5 => 1.0,
6 => 1.0005037081114851,
7 => 1.0,
8 => 4.6264742674547001,
9 => 15.686809055275578,
10 => 1.0,
11 => 11.903327742295504,
12 => 13.29050881934397,
13 => 1.0,
14 => 1.0,
15 => 3.5421134937189365,
16 => 1.0,
17 => 0.010999999999999999,
18 => 3.2999566681750605,
19 => 5,
20 => 1.2282984802843129,
21 => 1.0,
22 => 2.9748253120971184,
23 => 0.44855992975075798,
24 => 0.99999999999999989,
25 => 3.8350475954623371,
26 => 1.0625975061426283,
27 => 1.0000072792091179,
28 => 0.99999987785487132,
29 => 1,
30 => 0.0,
31 => 1.0,
32 => 1.0,
33 => 1.0,
34 => 0.0,
35 => 1.0972568578553616,
36 => 1.0,
37 => 1.4077661823957415,
38 => 1.0,
39 => 0.0,
40 => 3.6038030347555705,
41 => 1.0,
42 => 1.0,
43 => 1.0636876768842174,
44 => 1.0,
45 => NAN,
46 => 1.0,
47 => NAN,
48 => NAN,
49 => NAN,
50 => NAN,
51 => 1.0,
52 => 1.0,
53 => NAN,
54 => 0.99958680716631509,
55 => 1.0,
56 => NAN,
57 => 1.0, )
It seems as you actually do have discovered a bug. On large arrays containing NaN values, represented by the NAN constant in PHP, the built-in function sort fails.
The comparision with NaN should always result as non-ordered as mentioned by kuh-chan in the question comments. However, as soon as there is at least one operand NaN, in recent (March 2019) versions of PHP the spaceship operator <=> returns 1 (first operand greater than second one) and -1 (first operand less than second one) in some other versions.
echo var_dump( NAN <=> 1.23 );
echo var_dump( 1.23 <=> NAN );
echo var_dump( NAN <=> -1.23 );
echo var_dump( -1.23 <=> NAN );
echo var_dump( NAN <=> 0 );
echo var_dump( NAN <=> NAN );
I'm not very famimilar with the internals of the Zend engine. However, I guess the sort algorithm terminates too soon on large arrays with several NaN values, likely in order to the order comparision algorithm alway returns "greater (or less) than" which probably leads to multiple exchanges of the same elements.
I experienced that calling sort multiple times seems to continue the sorting. However, that would not be a proper workaround.
You can use a custom comparision algorithm with usort instead. If you want to order NaN at the start of the array, return -1 when the first operand is NaN, 1 when the second operand is NaN and 0 (equal) if both are. Otherwise return the comparision result of the spaceship operator.
usort($keys_arranged,
function(&$v1, &$v2)
{
switch( (is_nan($v1) ? 1 : 0) | (is_nan($v2) ? 2 : 0) )
{
case 0: return $v1 <=> $v2;
case 1: return -1;
case 2: return 1;
case 3: return 0;
}
}
);
Similar bitwise logic as above, but in a more compressive and direct form:
usort( $keys_arranged,
function(&$v1, &$v2){ return -2 === ($b = (is_nan($v1) ? -1 : -2) ^ (is_nan($v2) ? -1 : 0)) ? $v1 <=> $v2 : $b; }
);

How to remove wrong schema from an URL (with PHP)

I need to remove a wrong schema from an URL submitted as a string.
I start with this consideration:
The only two allowed schemas are http:// and https://
Starting from this consideration, I need to remove from the string all wrongly formatted schemas like:
htp://example.com
htps://example.com
http:/example.com
https:/example.com
htpexample.com
htps://example.com
http:/example.com
https:/example.com
... many many more ...
My questions are:
Is there a way to calculate all possible variation of wrong schemas?
Which is the best approach to remove them from the given string?
ABOUT QUESTION 2
My first approach would be to create an array with all the wrong schemas and then use something like this:
$wrongSchemas = [/* here all the possible wrong schemas calculated from question 1 */];
$url = str_replace($wrongSchemas, '', $url);
But this approach relies on a correct order, because instead I risk to remove partial schemas and make it wrong anyway.
And anyway I need to find a way to create the array $wrongSchemas!
Any suggestion or any further consideration on the topic that I'm missing, is well appreciated.
use strpos check in your $url
if(strpos($url,"http://")!==0 && strpos($url,"https://")!==0){
//wrong schemas
$exp_string = "";
// $exp_string = strpos($url,"//")?"//":"/";
if(strpos($url,"://"))
$exp_string = "://";
elseif(strpos($url,":/"))
$exp_string = ":/";
elseif(strpos($url,":"))
$exp_string = ":";
elseif(strpos($url,"//"))
$exp_string = "//";
$temp = explode($exp_string,$url);
if(count($temp)>1){
$url = '';
for($i=1;$i<count($temp);$i++){
$url = $url.$temp[$i];
}
//if needed you can add http:// here: $url = 'http://'.$url;
}
}
echo $url;
//process for right schemas
If you need more validations like url starting with ht,htp,etc you can use checkdnsrr or gethostbyname functions to validate domains
After some more thoughts, thanks also to some of your comments (thank you #Frédéric Clausset), I decided that the best approach would be to build the array of wrong schemas on the fly:
$schemas = ['http', 'htp', 'htt', 'ht', 'hp', 'ttp', 'tp'];
$delimiters = ['://', ':/', ':', '//', '/'];
$wrongCombinations = [];
foreach ($schemas as $wrongSchema) {
foreach ($delimiters as $wrongDelimiter) {
$combination = $wrongSchema . $wrongDelimiter;
$combinationSecure = $wrongSchema . 's' . $wrongDelimiter;
if ('http://' !== $combination) {
$wrongCombinations[] = $combination;
}
if ('https://' !== $combinationSecure) {
$wrongCombinations[] = $combinationSecure;
}
}
}
This generates a long array like this:
array:68 [▼
0 => "http:/"
1 => "https:/"
2 => "http:"
3 => "https:"
4 => "http//"
5 => "https//"
6 => "http/"
7 => "https/"
8 => "htp://"
9 => "htps://"
10 => "htp:/"
11 => "htps:/"
12 => "htp:"
13 => "htps:"
14 => "htp//"
15 => "htps//"
16 => "htp/"
17 => "htps/"
18 => "htt://"
19 => "htts://"
20 => "htt:/"
21 => "htts:/"
22 => "htt:"
23 => "htts:"
24 => "htt//"
25 => "htts//"
26 => "htt/"
27 => "htts/"
28 => "ht://"
29 => "hts://"
30 => "ht:/"
31 => "hts:/"
32 => "ht:"
33 => "hts:"
34 => "ht//"
35 => "hts//"
36 => "ht/"
37 => "hts/"
38 => "hp://"
39 => "hps://"
40 => "hp:/"
41 => "hps:/"
42 => "hp:"
43 => "hps:"
44 => "hp//"
45 => "hps//"
46 => "hp/"
47 => "hps/"
48 => "ttp://"
49 => "ttps://"
50 => "ttp:/"
51 => "ttps:/"
52 => "ttp:"
53 => "ttps:"
54 => "ttp//"
55 => "ttps//"
56 => "ttp/"
57 => "ttps/"
58 => "tp://"
59 => "tps://"
60 => "tp:/"
61 => "tps:/"
62 => "tp:"
63 => "tps:"
64 => "tp//"
65 => "tps//"
66 => "tp/"
67 => "tps/"
]
Those 68 combinations are all the possible wrong ones.
Now, a simple str_replace removes the schema if it is one of the wrong ones:
str_replace($combinations, '', $domain);
This intercept wrong URLs like:
htp://example.com > example.com
http:/example.com > example.com
htps:/example.com > example.com
hps:/example.com > example.com
htp:example.com > example.com
many many more
all possible variations
Thank you to all of you for your answers that helped me to better clarify the problem and find my solution! :)
PS
If you find bugs or drawbacks in this code, please, let me know!
I would search for :// if exists in string, after a then a simple in_array with the substring
$url="https://www.example.com";
$validschemas=array("http","https");
$pos=strpos($url,"://");
if($pos)
{
$valid=in_array(substr($url,0,$pos),$validschemas)?true:false;
//If not valid schema, remove schema from url, if it os ok dont touch it.
if(!$valid)
$url=substr($url,$pos+3);
}
else
{
//No schema, then url continues being the same
}

PHP FFT module error

I wrote a FFT (Fast Fourier Transform) module for PHP recently. When I tried to test it, It always throws an error that the array $this->reverseTable has some index not defined. I got no clue of how to solve this problem.
Here's the PHP code:
<?php
class FourierTransform {
public $bufferSize;
public $sampleRate;
public $bandwidth;
public $spectrum = array();
public $real = array();
public $imag = array();
public $peakBand = 0;
public $peak = 0;
public function __construct($bufferSize,$sampleRate){
$this->bufferSize = $bufferSize;
$this->sampleRate = $sampleRate;
$this->bandwidth = 2 / $bufferSize * $sampleRate / 2;
}
public function getBandFrequency($index){
return $this->bandwidth * $index + $this->bandwidth / 2;
}
public function calculateSpectrum(){
$bSi = 2 / $this->bufferSize;
for($i = 0,$N = $this->bufferSize/2; $i < $N; $i++){
$rval = $this->real[$i];
$ival = $this->imag[$i];
$mag = $bSi * sqrt($rval * $rval + $ival * $ival);
if($mag > $this->peak){
$this->peakBand = $i;
$this->peak = $mag;
}
$this->spectrum[$i] = $mag;
}
}
}
class FFT extends FourierTransform {
public $reverseTable = array();
public $sinTable = array();
public $cosTable = array();
public function __construct($bufferSize,$sampleRate){
parent::__construct($bufferSize,$sampleRate);
$limit = 1;
$bit = $bufferSize >> 1;
while($limit < $bufferSize){
for($i = 0; $i < $limit; $i++){
$this->reverseTable[$i + $limit] = $this->reverseTable[$i] + $bit;
}
$limit = $limit << 1;
$bit = $bit >> 1;
}
for($i = 0; $i < $bufferSize; $i++){
$this->sinTable[$i] = sin(-M_PI / $i);
$this->cosTable[$i] = cos(-M_PI / $i);
}
}
public function foward($buffer){
$k = floor(log($this->bufferSize,2));
if(pow(2,$k) !== $this->bufferSize) throw new Exception('Invalid buffer size, must be a power of 2.');
if($this->bufferSize !== count($buffer)) throw new Exception('Supplied buffer is not the same size as defined FFT.');
$halfSize = 1;
for($i = 0; $i < $this->bufferSize; $i++){
$this->real[$i] = $buffer[$this->reverseTable[$i]];
$this->imag[$i] = 0;
}
while($halfSize < $this->bufferSize){
$phaseShiftReal = $this->cosTable[$halfSize];
$phaseShiftImag = $this->sinTable[$halfSize];
$currentPhaseShiftReal = 1;
$currentPhaseShiftImag = 0;
for($fftStep = 0; $fftStep < $halfSize; $fftStep++){
while($fftStep < $this->bufferSize){
$off = $fftStep + $halfSize;
$tr = ($currentPhaseShiftReal * $this->real[$off]) - ($currentPhaseShiftImag * $this->imag[$off]);
$ti = ($currentPhaseShiftReal * $this->imag[$off]) + ($currentPhaseShiftImag * $this->real[$off]);
$this->real[$off] = $this->real[$fftStep] - $tr;
$this->imag[$off] = $this->imag[$fftStep] - $ti;
$this->real[$fftStep] += $tr;
$this->imag[$fftStep] += $ti;
$fftStep += $halfSize << 1;
}
$tmpReal = $currentPhaseShiftReal;
$currentPhaseShiftReal = ($tmpReal * $phaseShiftReal) - ($currentPhaseShiftImag * $phaseShiftImag);
$currentPhaseShiftImag = ($tmpReal * $phaseShiftImag) + ($currentPhaseShiftImag * $phaseShiftReal);
}
$halfSize = $halfSize << 1;
}
$this->calculateSpectrum();
}
}
?>
The test sample is a sine wave at 440Hz.
When I tried to run the code, it throws this error
Notice: Undefined offset: 0 in C:\Program Files
(x86)\EasyPHP-12.1\www\fft.php on line 48
continuously.
The array that has problem has data like this:
Array
(
[1] => 512
[2] => 256
[3] => 768
[4] => 128
[5] => 640
[6] => 384
[7] => 896
[8] => 64
[9] => 576
[10] => 320
[11] => 832
[12] => 192
[13] => 704
[14] => 448
[15] => 960
[16] => 32
[17] => 544
[18] => 288
[19] => 800
[20] => 160
[21] => 672
[22] => 416
[23] => 928
[24] => 96
[25] => 608
[26] => 352
[27] => 864
[28] => 224
[29] => 736
[30] => 480
[31] => 992
[32] => 16
[33] => 528
[34] => 272
[35] => 784
[36] => 144
[37] => 656
[38] => 400
[39] => 912
[40] => 80
[41] => 592
[42] => 336
[43] => 848
[44] => 208
[45] => 720
...
[978] => 303
[979] => 815
[980] => 175
[981] => 687
[982] => 431
[983] => 943
[984] => 111
[985] => 623
[986] => 367
[987] => 879
[988] => 239
[989] => 751
[990] => 495
[991] => 1007
[992] => 31
[993] => 543
[994] => 287
[995] => 799
[996] => 159
[997] => 671
[998] => 415
[999] => 927
[1000] => 95
[1001] => 607
[1002] => 351
[1003] => 863
[1004] => 223
[1005] => 735
[1006] => 479
[1007] => 991
[1008] => 63
[1009] => 575
[1010] => 319
[1011] => 831
[1012] => 191
[1013] => 703
[1014] => 447
[1015] => 959
[1016] => 127
[1017] => 639
[1018] => 383
[1019] => 895
[1020] => 255
[1021] => 767
[1022] => 511
[1023] => 1023
)
Edit: The previous problem is solved but now another problem is raised. At function forward() it throws an uncaught exception Invalid buffer size, must be a power of 2. Even if the buffer size is right.
Any help will be appreciated.
Assuming that this is the whole class, I presume that the issue lies on this line inside your FFT constructor:
$this->reverseTable[$i + $limit] = $this->reverseTable[$i] + $bit;
From what I can tell you declare reverseTable as an array, but this line is the only place in the class where any elements are added to that array, so the fact that you're setting the reverseTable[$i+$limit] element using a never-defined reverseTable[$i] value is going to give you problems in the first first iteration of that while loop when it tries to use the undefined index $i (reverseTable[$i]). You'll have to give reverseTable[0] a value before you enter that loop.
Although you didn't provide where the line was, my guess is it has something to do with this line:
$this->reverseTable[$i + $limit] = $this->reverseTable[$i] + $bit;
This is in your constructor, and this bit especially looks wrong $this->reverseTable[$i] + $bit;. You are asking for the value from the reverseTable array, but this key is not initialized anywhere in the constructor.
I am not sure how to fix this, as it is a logic error on your part.

PHP: Convert unicode codepoint to UTF-8

I have my data in this format: U+597D or like this U+6211. I want to convert them to UTF-8 (original characters are 好 and 我). How can I do it?
$utf8string = html_entity_decode(preg_replace("/U\+([0-9A-F]{4})/", "&#x\\1;", $string), ENT_NOQUOTES, 'UTF-8');
is probably the simplest solution.
function utf8($num)
{
if($num<=0x7F) return chr($num);
if($num<=0x7FF) return chr(($num>>6)+192).chr(($num&63)+128);
if($num<=0xFFFF) return chr(($num>>12)+224).chr((($num>>6)&63)+128).chr(($num&63)+128);
if($num<=0x1FFFFF) return chr(($num>>18)+240).chr((($num>>12)&63)+128).chr((($num>>6)&63)+128).chr(($num&63)+128);
return '';
}
function uniord($c)
{
$ord0 = ord($c{0}); if ($ord0>=0 && $ord0<=127) return $ord0;
$ord1 = ord($c{1}); if ($ord0>=192 && $ord0<=223) return ($ord0-192)*64 + ($ord1-128);
$ord2 = ord($c{2}); if ($ord0>=224 && $ord0<=239) return ($ord0-224)*4096 + ($ord1-128)*64 + ($ord2-128);
$ord3 = ord($c{3}); if ($ord0>=240 && $ord0<=247) return ($ord0-240)*262144 + ($ord1-128)*4096 + ($ord2-128)*64 + ($ord3-128);
return false;
}
utf8() and uniord() try to mirror the chr() and ord() functions on php:
echo utf8(0x6211)."\n";
echo uniord(utf8(0x6211))."\n";
echo "U+".dechex(uniord(utf8(0x6211)))."\n";
//In your case:
$wo='U+6211';
$hao='U+597D';
echo utf8(hexdec(str_replace("U+","", $wo)))."\n";
echo utf8(hexdec(str_replace("U+","", $hao)))."\n";
output:
我
25105
U+6211
我
好
PHP 7+
As of PHP 7, you can use the Unicode codepoint escape syntax to do this.
echo "\u{597D}"; outputs 好.
I just wrote a polyfill for missing multibyte versions of ord and chr with the following in mind:
It defines functions mb_ord and mb_chr only if they don't already exist. If they do exist in your framework or some future version of PHP, the polyfill will be ignored.
It uses the widely used mbstring extension to do the conversion. If the mbstring extension is not loaded, it will use the iconv extension instead.
I also added functions for HTMLentities encoding / decoding and encoding / decoding to JSON format as well as some demo code for how to use these functions
Code
if (!function_exists('codepoint_encode')) {
function codepoint_encode($str) {
return substr(json_encode($str), 1, -1);
}
}
if (!function_exists('codepoint_decode')) {
function codepoint_decode($str) {
return json_decode(sprintf('"%s"', $str));
}
}
if (!function_exists('mb_internal_encoding')) {
function mb_internal_encoding($encoding = NULL) {
return ($from_encoding === NULL) ? iconv_get_encoding() : iconv_set_encoding($encoding);
}
}
if (!function_exists('mb_convert_encoding')) {
function mb_convert_encoding($str, $to_encoding, $from_encoding = NULL) {
return iconv(($from_encoding === NULL) ? mb_internal_encoding() : $from_encoding, $to_encoding, $str);
}
}
if (!function_exists('mb_chr')) {
function mb_chr($ord, $encoding = 'UTF-8') {
if ($encoding === 'UCS-4BE') {
return pack("N", $ord);
} else {
return mb_convert_encoding(mb_chr($ord, 'UCS-4BE'), $encoding, 'UCS-4BE');
}
}
}
if (!function_exists('mb_ord')) {
function mb_ord($char, $encoding = 'UTF-8') {
if ($encoding === 'UCS-4BE') {
list(, $ord) = (strlen($char) === 4) ? #unpack('N', $char) : #unpack('n', $char);
return $ord;
} else {
return mb_ord(mb_convert_encoding($char, 'UCS-4BE', $encoding), 'UCS-4BE');
}
}
}
if (!function_exists('mb_htmlentities')) {
function mb_htmlentities($string, $hex = true, $encoding = 'UTF-8') {
return preg_replace_callback('/[\x{80}-\x{10FFFF}]/u', function ($match) use ($hex) {
return sprintf($hex ? '&#x%X;' : '&#%d;', mb_ord($match[0]));
}, $string);
}
}
if (!function_exists('mb_html_entity_decode')) {
function mb_html_entity_decode($string, $flags = null, $encoding = 'UTF-8') {
return html_entity_decode($string, ($flags === NULL) ? ENT_COMPAT | ENT_HTML401 : $flags, $encoding);
}
}
How to use
echo "\nGet string from numeric DEC value\n";
var_dump(mb_chr(25105));
var_dump(mb_chr(22909));
echo "\nGet string from numeric HEX value\n";
var_dump(mb_chr(0x6211));
var_dump(mb_chr(0x597D));
echo "\nGet numeric value of character as DEC int\n";
var_dump(mb_ord('我'));
var_dump(mb_ord('好'));
echo "\nGet numeric value of character as HEX string\n";
var_dump(dechex(mb_ord('我')));
var_dump(dechex(mb_ord('好')));
echo "\nEncode / decode to DEC based HTML entities\n";
var_dump(mb_htmlentities('我好', false));
var_dump(mb_html_entity_decode('我好'));
echo "\nEncode / decode to HEX based HTML entities\n";
var_dump(mb_htmlentities('我好'));
var_dump(mb_html_entity_decode('我好'));
echo "\nUse JSON encoding / decoding\n";
var_dump(codepoint_encode("我好"));
var_dump(codepoint_decode('\u6211\u597d'));
Output
Get string from numeric DEC value
string(3) "我"
string(3) "好"
Get string from numeric HEX value
string(3) "我"
string(3) "好"
Get numeric value of character as DEC string
int(25105)
int(22909)
Get numeric value of character as HEX string
string(4) "6211"
string(4) "597d"
Encode / decode to DEC based HTML entities
string(16) "我好"
string(6) "我好"
Encode / decode to HEX based HTML entities
string(16) "我好"
string(6) "我好"
Use JSON encoding / decoding
string(12) "\u6211\u597d"
string(6) "我好"
mb_convert_encoding(
preg_replace("/U\+([0-9A-F]*)/"
,"&#x\\1;"
,'U+597DU+6211'
)
,"UTF-8"
,"HTML-ENTITIES"
);
works fine, too.
<?php
function chr_utf8($n,$f='C*'){
return $n<(1<<7)?chr($n):($n<1<<11?pack($f,192|$n>>6,1<<7|191&$n):
($n<(1<<16)?pack($f,224|$n>>12,1<<7|63&$n>>6,1<<7|63&$n):
($n<(1<<20|1<<16)?pack($f,240|$n>>18,1<<7|63&$n>>12,1<<7|63&$n>>6,1<<7|63&$n):'')));
}
$your_input='U+597D';
echo (chr_utf8(hexdec(ltrim($your_input,'U+'))));
// Output 好
If you want to use a callback function you can try it :
<?php
// Note: function chr_utf8 shown above is required
$your_input='U+597DU+6211';
$result=preg_replace_callback('#U\+([a-f0-9]+)#i',function($a){return chr_utf8(hexdec($a[1]));},$your_input);
echo $result;
// Output 好我
Check it in https://eval.in/748187
I was in the position I needed to filter specific characters without affecting the html because I was using a wysiwig editor, but people copy pasting from word would add some nice unrenderable characters to the content.
My solution boils down to simple replacement lists.
class ReplaceIllegal {
public static $find = array ( 0 => '\x0', 1 => '\x1', 2 => '\x2', 3 => '\x3', 4 => '\x4', 5 => '\x5', 6 => '\x6', 7 => '\x7', 8 => '\x8', 9 => '\x9', 10 => '\xA', 11 => '\xB', 12 => '\xC', 13 => '\xD', 14 => '\xE', 15 => '\xF', 16 => '\x10', 17 => '\x11', 18 => '\x12', 19 => '\x13', 20 => '\x14', 21 => '\x15', 22 => '\x16', 23 => '\x17', 24 => '\x18', 25 => '\x19', 26 => '\x1A', 27 => '\x1B', 28 => '\x1C', 29 => '\x1D', 30 => '\x1E', 31 => '\x80', 32 => '\x81', 33 => '\x82', 34 => '\x83', 35 => '\x84', 36 => '\x85', 37 => '\x86', 38 => '\x87', 39 => '\x88', 40 => '\x89', 41 => '\x8A', 42 => '\x8B', 43 => '\x8C', 44 => '\x8D', 45 => '\x8E', 46 => '\x8F', 47 => '\x90', 48 => '\x91', 49 => '\x92', 50 => '\x93', 51 => '\x94', 52 => '\x95', 53 => '\x96', 54 => '\x97', 55 => '\x98', 56 => '\x99', 57 => '\x9A', 58 => '\x9B', 59 => '\x9C', 60 => '\x9D', 61 => '\x9E', 62 => '\x9F', 63 => '\xA0', 64 => '\xA1', 65 => '\xA2', 66 => '\xA3', 67 => '\xA4', 68 => '\xA5', 69 => '\xA6', 70 => '\xA7', 71 => '\xA8', 72 => '\xA9', 73 => '\xAA', 74 => '\xAB', 75 => '\xAC', 76 => '\xAD', 77 => '\xAE', 78 => '\xAF', 79 => '\xB0', 80 => '\xB1', 81 => '\xB2', 82 => '\xB3', 83 => '\xB4', 84 => '\xB5', 85 => '\xB6', 86 => '\xB7', 87 => '\xB8', 88 => '\xB9', 89 => '\xBA', 90 => '\xBB', 91 => '\xBC', 92 => '\xBD', 93 => '\xBE', 94 => '\xBF', 95 => '\xC0', 96 => '\xC1', 97 => '\xC2', 98 => '\xC3', 99 => '\xC4', 100 => '\xC5', 101 => '\xC6', 102 => '\xC7', 103 => '\xC8', 104 => '\xC9', 105 => '\xCA', 106 => '\xCB', 107 => '\xCC', 108 => '\xCD', 109 => '\xCE', 110 => '\xCF', 111 => '\xD0', 112 => '\xD1', 113 => '\xD2', 114 => '\xD3', 115 => '\xD4', 116 => '\xD5', 117 => '\xD6', 118 => '\xD7', 119 => '\xD8', 120 => '\xD9', 121 => '\xDA', 122 => '\xDB', 123 => '\xDC', 124 => '\xDD', 125 => '\xDE', 126 => '\xDF', 127 => '\xE0', 128 => '\xE1', 129 => '\xE2', 130 => '\xE3', 131 => '\xE4', 132 => '\xE5', 133 => '\xE6', 134 => '\xE7', 135 => '\xE8', 136 => '\xE9', 137 => '\xEA', 138 => '\xEB', 139 => '\xEC', 140 => '\xED', 141 => '\xEE', 142 => '\xEF', 143 => '\xF0', 144 => '\xF1', 145 => '\xF2', 146 => '\xF3', 147 => '\xF4', 148 => '\xF5', 149 => '\xF6', 150 => '\xF7', 151 => '\xF8', 152 => '\xF9', 153 => '\xFA', 154 => '\xFB', 155 => '\xFC', 156 => '\xFD', 157 => '\xFE', );
private static $replace = array ( 0 => '', 1 => '', 2 => '', 3 => '', 4 => '', 5 => '', 6 => '', 7 => '', 8 => '', 9 => ' ', 10 => '
', 11 => '', 12 => '', 13 => '
', 14 => '', 15 => '', 16 => '', 17 => '', 18 => '', 19 => '', 20 => '', 21 => '', 22 => '', 23 => '', 24 => '', 25 => '', 26 => '', 27 => '', 28 => '', 29 => '', 30 => '', 31 => '€', 32 => '', 33 => '‚', 34 => 'ƒ', 35 => '„', 36 => '…', 37 => '†', 38 => '‡', 39 => 'ˆ', 40 => '‰', 41 => 'Š', 42 => '‹', 43 => 'Œ', 44 => '', 45 => 'Ž', 46 => '', 47 => '', 48 => '‘', 49 => '’', 50 => '“', 51 => '”', 52 => '•', 53 => '–', 54 => '—', 55 => '˜', 56 => '™', 57 => 'š', 58 => '›', 59 => 'œ', 60 => '', 61 => 'ž', 62 => 'Ÿ', 63 => ' ', 64 => '¡', 65 => '¢', 66 => '£', 67 => '¤', 68 => '¥', 69 => '¦', 70 => '§', 71 => '¨', 72 => '©', 73 => 'ª', 74 => '«', 75 => '¬', 76 => '­', 77 => '®', 78 => '¯', 79 => '°', 80 => '±', 81 => '²', 82 => '³', 83 => '´', 84 => 'µ', 85 => '¶', 86 => '·', 87 => '¸', 88 => '¹', 89 => 'º', 90 => '»', 91 => '¼', 92 => '½', 93 => '¾', 94 => '¿', 95 => 'À', 96 => 'Á', 97 => 'Â', 98 => 'Ã', 99 => 'Ä', 100 => 'Å', 101 => 'Æ', 102 => 'Ç', 103 => 'È', 104 => 'É', 105 => 'Ê', 106 => 'Ë', 107 => 'Ì', 108 => 'Í', 109 => 'Î', 110 => 'Ï', 111 => 'Ð', 112 => 'Ñ', 113 => 'Ò', 114 => 'Ó', 115 => 'Ô', 116 => 'Õ', 117 => 'Ö', 118 => '×', 119 => 'Ø', 120 => 'Ù', 121 => 'Ú', 122 => 'Û', 123 => 'Ü', 124 => 'Ý', 125 => 'Þ', 126 => 'ß', 127 => 'à', 128 => 'á', 129 => 'â', 130 => 'ã', 131 => 'ä', 132 => 'å', 133 => 'æ', 134 => 'ç', 135 => 'è', 136 => 'é', 137 => 'ê', 138 => 'ë', 139 => 'ì', 140 => 'í', 141 => 'î', 142 => 'ï', 143 => 'ð', 144 => 'ñ', 145 => 'ò', 146 => 'ó', 147 => 'ô', 148 => 'õ', 149 => 'ö', 150 => '÷', 151 => 'ø', 152 => 'ù', 153 => 'ú', 154 => 'û', 155 => 'ü', 156 => 'ý', 157 => 'þ', );
/*
* replace illegal characters for escaped html character but don't touch anything else.
*/
public static function getSaveValue($value) {
return str_replace(self::$find, self::$replace, $value);
}
public static function makeIllegal($find,$replace) {
self::$find[] = $find;
self::$replace[] = $replace;
}
}
This worked fine for me. If you have a string "Letters u00e1 u00e9 etc." replace by "Letters á é".
function unicode2html($str){
// Set the locale to something that's UTF-8 capable
setlocale(LC_ALL, 'en_US.UTF-8');
// Convert the codepoints to entities
$str = preg_replace("/u([0-9a-fA-F]{4})/", "&#x\\1;", $str);
// Convert the entities to a UTF-8 string
return iconv("UTF-8", "ISO-8859-1//TRANSLIT", $str);
}
With the aid of the following table:
http://en.wikipedia.org/wiki/UTF-8#Description
can't be simpler :)
Simply mask the unicode numbers according to which range they fit in.

Categories