I'm looking to use unpack().
This works:
$srbytes = "\x80\x3e\x00\x00";
$array1 = unpack("v",$srbytes);
This does not:
$num1 = "80"
$srbytes = "\x".$num1."\x3e\x00\x00";
$array1 = unpack("v",$srbytes);
or
$srbytes = "\x"."80\x3e\x00\x00";
$array1 = unpack("v",$srbytes);
Printing this with echo shows ASCII chars with the first full string but, the concatenated ones shows text until it passes where it was concatenated.
Comparing a full string against a concatenated ones shows false, even though they should be the same?
what is actually happening when I'm trying to concatenate
The character expansion won't work, because at the point that you do "\x" . "80" PHP already has two string literals. It can't be expected to figure that meant anything else but this.
Instead of trying to concatenate a hexadecimal value for expansion, just concatenate the actual character, by converting the hexadecimal value to a base10 integer, and passing it to chr(), which converts it to an actual byte.
$str = "";
$num1 = "80";
$str .= chr(base_convert($num1, 16, 10));
var_dump($str);
Gives you
string(1) "�"
When you actually look at the value of $srbytes in your example where you define it as a string literal "\x80\x3e\x00\x00", what you get is var_dump("\x80\x3e\x00\x00") giving you string(4) "�>", because PHP double quoted strings offer additional character expansion such as expanding on escaped hexadecimal values into bytes. However, var_dump("\x"."80\x3e\x00\x00") just gives you string(7) "\x80>", which is because the value "\x" by itself is just a literal "\x" as a string. So they aren't the same values, no.
If you want the 'literal' string use single quotes. Your issue is with escaped character sequences inside double quotes being evaluated. Example:
$srbytes = '\x'.'80\x3e\x00\x00';
echo $srbytes;
// \x80\x3e\x00\x00
var_dump($srbytes);
// string(16) "\x80\x3e\x00\x00"
$srbytes = "\x"."80\x3e\x00\x00";
echo $srbytes;
// \x80>
var_dump($srbytes);
//string(7) "\x80>"
http://php.net/manual/en/language.types.string.php
Related
I've got a string representing an IPv4 address:
$ip = '\x7F\0\0\x01';
When I try to pass that to inet_ntop($ip) it's giving me grief:
PHP Warning: inet_ntop(): Invalid in_addr value
If I declare the variable manually using double quotes it works:
$ip = "\x7F\0\0\x01";
inet_ntop($ip); // "127.0.0.1"
However, I am not declaring these variables manually. I'm working with what is given to me in an object.
How can I convert '\x7F\0\0\x01' into a string that inet_ntop() will accept?
In other words, how can I make PHP parse a string literally as if I were manually declaring it with double quotes?
Some interesting facts:
gettype('\x7F\0\0\x01'); // string
gettype("\x7F\0\0\x01"); // string
ord('\x7F\0\0\x01'); // 92
ord("\x7F\0\0\x01"); // 127
implode(unpack('H*', '\x7F\0\0\x01')); // 5c7837465c305c305c783031
implode(unpack('H*', "\x7F\0\0\x01")); // 7f000001
mb_detect_encoding('\x7F\0\0\x01'); // ASCII
mb_detect_encoding("\x7F\0\0\x01"); // UTF-8
"\x7F\0\0\x01" == '\x7F\0\0\x01'; // false
// and for the haters
long2ip('\x7F\0\0\x01'); // PHP Warning: long2ip() expects parameter 1 to be integer, string given
One possibility is to parse the string into its component pieces (starting with \); convert them to the decimal equivalent and use chr to get back the original characters. These can then be joined into a string which is suitable for inet_ntop:
$ip = '\x7F\0\0\x01';
preg_match_all('/\\\x?([\dA-F]+)/', $ip, $parts);
$ip = implode('', array_map(function ($v) { return chr(hexdec($v)); }, $parts[1]));
echo inet_ntop($ip);
Another alternative is to use pack, after stripping out the \x parts and replacing \0 with 00:
$ip = '\x7F\0\0\x01';
$ip = pack('H*', str_replace(array('\x', '\0'), array('', '00'), $ip));
echo inet_ntop($ip);
In both cases the output is:
127.0.0.1
Demo on 3v4l.org
The problem is that you've got the literal ASCII output of a binary string and not the real binary value you expect it to be. I'm not sure how you got the literal ASCII value. There is a way to convert it, but you're not going to like it.
You can use eval() to accomplish what you're trying to do. All arguments for eval() being evil still apply.
$ip = '\x7F\0\0\x01';
eval("\$ip = \"$ip\";");
echo inet_ntop($ip);
This will print out 127.0.0.1.
Since binary doesn’t always result in literal ASCII characters, I worry you’ll see literal characters like � in the strings, and these won’t convert properly to the binary value you expect them to be.
For example, here are the characters printed to screen in Psysh:
>>> hex2bin('7f000001') // This is 127.0.0.1
=> "\x7F\0\0\x01"
>>> hex2bin('ffffffff') // This is 255.255.255.255
=> b"ÿÿÿÿ"
The first value looks familiar, right? That's the string literal that we can convert back into a binary string using eval(), like we did in the example above. But the binary value for ffffffff is a different story. If we try to convert it, it doesn't give us the 255.255.255.255 value we expect.
$ip = 'ÿÿÿÿ';
eval("\$ip = \"$ip\";");
echo inet_ntop($ip);
In this case, inet_ntop() returns false, but we know it should work:
>>> inet_ntop(hex2bin('ffffffff'));
=> "255.255.255.255"
So, I worry that any attempt to convert these values from string literals into binary strings is not going to work in all cases, whether using eval() or any of the other answers provided here.
However, if everything is coming to you in the format \0\0\0\0, where each "segment" is either a zero or a hex value in the format x00, then you should be in good shape, because these are the same:
>>> "\xFF\xFF\xFF\xFF"
=> b"ÿÿÿÿ"
You can make your own function like this
function convertStringToInAddr(string $string) {
$return = null;
$exploded = explode("\\", $string);
foreach($exploded as $hex) {
if( $hex != "" ) {
$return .= chr(hexdec(str_replace("x", "", $hex)));
}
}
return $return;
}
I have a (simplified) JSON response from an API call that looks like below
{"status":true,"action_values":"{\n \"range_from\": \"0\",\n \"range_to\": \"0\"\n}"}
I am trying to remove the \n characters from above using PHP but it doesn't seem to be working.
I try:
$trimmed = str_replace("\n", "", $response);
Where $response is my JSON string as above. But this does not remove/replace the \n character.
There is no need to remove the \n / new-lines.
Instead you should decode your string using json_decode() and then you can decode the range_from value, which is also json encoded inside your original json:
<?php
$str = '{"status":true,"action_values":"{\n \"range_from\": \"0\",\n \"range_to\": \"0\"\n}"}';
$dec = json_decode($str, true);
var_dump(json_decode($dec['action_values'], true));
Result:
array(2) {
["range_from"]=>
string(1) "0"
["range_to"]=>
string(1) "0"
}
An example.
I would recommend the solution by #jeroen, since it makes use of PHPs native functions to handle JSON.
However, since you've asked, I sense that you do not completely understand why your solution did not work.
As already pointed out in the comments by #B001 you need "\\n" for this task:
$trimmed = str_replace("\\n", "", $response);
The reason for this is, that "\n" represents the new line character when "\\n" represents the string "\n".
Try the following code and you will see the difference
print("-----");
print("\n");
print("-----");
print("\\n");
print("-----");
print("\"");
Which will result in the following output:
-----
-----\n-----"
The reason for this is that every instance of the "\" character in code, starts a control character. Examples for this are "\n" for newline, "\r" for carriage return, "\t" for tab, \" for the "-character inside a string defined by "" and "\\" for the actual backslash-character.
So if you want to create the actual string containing \n, you have to tell the interpreter that you actually want the \-character and not a control character created by \ and what ever character follows. This is done by using double backslashes "\\" which is the string representation of the actual backslash string. This is called "escaping".
In your case you have the actual character string in your $response variable, and you therefore have to use the escaped character as pattern.
Last let me explain the difference between "\n" and '\n'.
There are two ways in PHP to create a string:
$str1 = "hello \n world\n";
$str2 = 'hello \n world\n';
print($str1);
print($str2);
Both variables will contain a string, however, the "-string indicates for the PHP interpreter that the contained string should be interpreted, while the '-string gives you the string as it is. The example above would therefor result in the following output:
hello
world
hello \n world\n
This shows that the following code also would strip your string of the \n instances since '\n' would contain the actual string and not the control character:
$trimmed = str_replace('\n', "", $response);
This interpretation of the "-string goes so far as to allow for variables to be inserted into a string:
$name = "Daniel";
$age = 18;
$sentence = "My Friend $name is $age years old.";
print($sentence);
and would result in:
My Friend Daniel is 18 years old.
I know this question asked here many times.But That solutions are not useful for me. I am facing this problem very badly today.
// Case 1
$str = 'Test \300'; // Single Quoted String
echo json_encode(utf8_encode($str)) // output: Test \\300
// Case 2
$str = "Test \300"; // Double Quoted String
echo json_encode(utf8_encode($str)) // output: Test \u00c0
I want case 2's output and I have single quoted $str variable. This variable is filled from XML string parsing . And that XML string is saved in txt file.
(Here \300 is encoding of À (latin Charactor) character and I can't control it.)
Please Don't give me solution for above static string
Thanks in advance
This'll do:
$string = '\300';
$string = preg_replace_callback('/\\\\\d{1,3}/', function (array $match) {
return pack('C', octdec($match[0]));
}, $string);
It matches any sequence of a backslash followed by up to three numbers and converts that number from an octal number to a binary string. Which has the same result as what "\300" does.
Note that this will not work exactly the same for escaped escapes; i.e. "\\300" will result in a literal \300 while the above code will convert it.
If you want all the possible rules of double quoted strings followed without reimplementing them by hand, your best bet is to simply eval("return \"$string\""), but that has a number of caveats too.
May You are looking for this
$str = 'Test \300'; // Single Quoted String
echo json_encode(stripslashes($str)); // output: Test \\300
$fr = "hammad";
$frhammad = "nuthing";
echo $fr{$fr};
Output:
h
Whereas the expected output was
"Nuthing"
What Should be the format to echo "Nuthing"?
Because $x{$n} is standard syntax that treats the string $x as an array of characters, where $n is the numeric index position of a character in that aray. In your case the index position is identified by $fr, which is a non-numeric string, so PHP's loose typing is converting it to an integer 0, and so echoing the character at position 0... the first character of the string
EDIT
obligatory quote from the manual:
String access and modification by character
Characters within strings may be accessed and modified by specifying the zero-based offset of the desired character after the string using square array brackets, as in $str[42]. Think of a string as an array of characters for this purpose. The functions substr() and substr_replace() can be used when you want to extract or replace more than 1 character.
Note: Strings may also be accessed using braces, as in $str{42}, for the same purpose.
EDIT #2
To answer your latest question from the comments:
how would I concatenate the name of variables as I have given in it
question?
$fr = "hammad";
$frhammad = "nuthing";
$varName = 'fr'.$fr;
echo $$varName;
or
$fr = "hammad";
$frhammad = "nuthing";
echo ${'fr'.$fr};
The correct syntax for variable-variable interpolation is:
$fr = "hammad";
$frhammad = "nuthing";
echo ${fr.$fr};
I have two strings that look the same when I echo them, but when I var_dump() them they are different string types:
Echo:
http://blah
http://blah
var dump:
string(14) "http://blah"
string(11) "http://blah"
strToHex:
%68%74%74%70%3a%2f%2f%62%6c%61%68%00%00%00
%68%74%74%70%3a%2f%2f%62%6c%61%68
When I compare them, they return false. How can I manipulate the string type, so that I can perform a comparison that returns true?
What is the difference between string 11 and string 14? I am sure there is a simple resolution, but I have not found anything yet. No matter how I implode, explode, UTF-8 encode, etc., they will not compare the strings or change type.
Letter "a" can be written in another encoding.
For example: blаh. Here a is a Cyrillic 'а'.
All of these letters are Cyrillic, but it looks like Latin: у, е, х, а, р, о, с
Trim the strings before comparing. There are escaped characters, like \t and \n, which are not visible.
$clean_str = trim($str);
When using var_dump(), then string(14) means that the value is a string that holds 14 bytes. So string(11) and string(14) are not different "types" of strings; they are just strings of different length.
I would use something like this to see what actually is inside those strings:
function strToHex($value, $prefix = '') {
$result = '';
$length = strlen($value);
for ( $n = 0; $n < $length; $n++ ) {
$result .= $prefix . sprintf('%02x', ord($value[$n]));
}
return $result;
}
echo strToHex("test\r\n", '%');
Output:
%74%65%73%74%0d%0a
This decodes as:
%74 - t
%65 - e
%73 - s
%74 - t
%0d - \r (carriage return)
%0a - \n (line feed)
Or, as pointed out in comments by Karolis, you can use the built-in function bin2hex():
echo bin2hex("test\r\n");
Output:
746573740d0a
Try to trim these strings:
if (trim($string1) == trim($string2)) {
// Do things
}
Probably Unicode strings within the upper range are counted as double bytes.
Use mb_strlen() to check lengths.
Also some characters may not be visible, but present (there are many of Unicode spaces, etc.)
Generally, when you work with Unicode functions, you should use the mb_* string functions.
You may overload string encoding functions in php.ini to always use mb_* functions instead the standard ones (I am not sure if Xdebug honors those settings).
In PHP 6 this problem will be solved, as it should be globally Unicode-aware.