My testcase as follows:
echo crypt('string', '_....salt');//error
echo crypt('string', '_A...salt');//fast
echo crypt('string', '_AAAAsalt');//slow
Explanation as stated at http://www.php.net/manual/en/function.crypt.php:
CRYPT_EXT_DES - Extended DES-based hash. The "salt" is a 9-character
string consisting of an underscore followed by 4 bytes of iteration
count and 4 bytes of salt. These are encoded as printable characters,
6 bits per character, least significant character first. The values 0
to 63 are encoded as "./0-9A-Za-z". Using invalid characters in the
salt will cause crypt() to fail.
A dot is a printable character so why does it return an error? And which "order" applies on the used characters resulting "AAAA" more iterations than "A..."?
It says all in the quoted paragraph:
- least significant character first
- The values 0 to 63 are encoded as "./0-9A-Za-z"
So in your example "_....salt" would mean 0 rounds which obviously can't work.
and "_A...salt" is less than "_AAAAsalt" considering the least significant character comes first.
"_...Asalt" would also be more than "_A...salt"
This question is a bit old, however i found this when trying to wrap my head around how to create a hashing class for internal use here, and i came up with this little function which will base64 encode an integer with the appropriate characters/significance to be used as the 4 character 'iteration count'. Possible values are from 1 to 16,777,215
private function base64_int_encode($num){
$alphabet_raw = "./0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
$alphabet = str_split($alphabet_raw);
$arr = array();
$base = sizeof($alphabet);
while($num){
$rem = $num % $base;
$num = (int)($num / $base);
$arr[]=$alphabet[$rem];
}
$arr = array_reverse($arr);
$string = implode($arr);
return str_pad($string, 4, '.', STR_PAD_LEFT);
}
Hope it helps someone!
The code of Klathmon is nice but has some mistakes:
First - alphabet
It is:
./0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
Should be:
./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
Second - order of characters/digits
It generates for example: ...z
But it should generate: z...
The improved code:
function base64_int_encode($num) {
$alphabet_raw='./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
$alphabet=str_split($alphabet_raw);
$arr=array();
$base=sizeof($alphabet);
while($num) {
$rem=$num % $base;
$num=(int)($num / $base);
$arr[]=$alphabet[$rem];
}
$string=implode($arr);
return str_pad($string, 4, '.', STR_PAD_RIGHT);
}
A number system used in Extended DES:
.... - 0 (Extended DES error)
/... - 1
0... - 2
1... - 3
2... - 4
3... - 5
4... - 6
5... - 7
6... - 8
7... - 9
8... - 10
z... - 63
./.. - 64
//.. - 65
0/.. - 66
1/.. - 67
Y/.. - 100
61.. - 200
g2.. - 300
E4.. - 400
o5.. - 500
M7.. - 600
w8.. - 700
UA.. - 800
2C.. - 900
cD.. - 1000
zz.. - 4095
../. - 4096
/./. - 4097
0./. - 4098
1./. - 4099
xzzz - 16 777 213
yzzz - 16 777 214
zzzz - 16 777 215
And in connection with salt:
_/...salt - 1
_0...salt - 2
_1...salt - 3
_2...salt - 4
_3...salt - 5
_4...salt - 6
_5...salt - 7
_6...salt - 8
_7...salt - 9
_8...salt - 10
_z...salt - 63
_./..salt - 64
_//..salt - 65
_0/..salt - 66
_1/..salt - 67
_Y/..salt - 100
_61..salt - 200
_g2..salt - 300
_E4..salt - 400
_o5..salt - 500
_M7..salt - 600
_w8..salt - 700
_UA..salt - 800
_2C..salt - 900
_cD..salt - 1000
_zz..salt - 4095
_../.salt - 4096
_/./.salt - 4097
_0./.salt - 4098
_1./.salt - 4099
_xzzzsalt - 16 777 213
_yzzzsalt - 16 777 214
_zzzzsalt - 16 777 215
Related
This question already has answers here:
Is floating point math broken?
(31 answers)
Closed 3 years ago.
for($i=0;$i<=15120;$i+=504){
echo ($i/60/8.4) . " - " .floor($i/60/8.4)."<br>";
}
Result (i make ** at problem) :
0 - 0
1 - 1
2 - 2
3 - 3
4 - 4
5 - 5
6 - 6
7 - 6
8 - 8
9 - 8
10 - 10
11 - 11
12 - 12
13 - 13
14 - 13
15 - 15
16 - 16
17 - 17
18 - 17
etc...
At start i think i apply "Floo" at all calculation but (for line "7-6") also $i = 3528 :
3528 / 60 = 58,8 == Floor ==> 58 / 8 = 7.25
floor of 7.25 =/= 6
it because of PHPs floating point precision
so your 8th calculation for example will not return 7, but something like 6.9999999999999999999999999999
as this is a double, it will be rounded to 7 on output, try this out:
$x = 6.9999999999999999999999999999999999999999999999999999999;
echo $x;
when you use floor() it will (correctly) round it down to 6
Let’s say I have a series of numbers like:
12345678910111213141516... (until unlimited)
Then I would like to get a number from it by given digit. For example:
Digit 10th: 1
Digit 17th: 3
...
I have tried to make the algorithm to do it by using PHP but it always showed me an error due to the looping that I made was out of memory size if the given digit that I gave is more than 10.000.000. Allowed Memory Size of 134217728 Bytes Exhausted
How do I deal with this without having to modify memory_limit on php.ini file?
Here are what I have tried to figure the algorithm out: I benchmark the maximum of upper limit of the loop that my local machine could handle, and I found out it's 10.000.000, then I assumed I need to make a separate loop if the given digit/parameter is more than 10.000.000. But in the end I still got that error of out of memory size. Really grateful in advance.
<?php
/*
* benchmark result:
* max digit = 10.000.000
*/
$benchmarkedDigit = 10000000;
$digit = 1000000000000; // it could be dynamically assigned, i.e. a parameter. In this case will show an error since the given digit is 10 trillion
$s = '';
if ($digit > $benchmarkedDigit) {
$mod = fmod($digit, $benchmarkedDigit);
$div = $digit / $benchmarkedDigit;
for ($x = 1; $x <= $div; $x++) {
$upperLimit = ($x * $benchmarkedDigit);
for ($y = ($upperLimit - $benchmarkedDigit + 1); $y <= $upperLimit; $y++) {
$s .= $y;
}
// so it could be:
// 1 - 10.000.000
// 10.000.001 - 20.000.000
// 20.000.001 - 30.000.000
// ...
}
// loop for the rest of the fmod(), if its result is not 0
for ($i = ($upperLimit + 1); $i <= ($upperLimit + $mod); $i++) {
$s .= $i;
}
} else {
for ($x = 1; $x <= $digit; $x++) {
$s .= $x;
}
}
echo substr($s, ($digit - 1), 1);
You can use the fact that there's always 10^n - 10^(n-1) number of n-digit long numbers (even 1 digit, because I see 0 is not there).
With this knowledge, you can skip potentially huge number of numbers.
You start with n=1, and check if the number of n digit numbers is lower than the desired digit. If it is, then reduce the number of n digit numbers from the desired number, increase n by one and start again.
For example: you want to know the 512th digit in that number
Is the number of 1 digit numbers (10) lower than the desired digit (512)?
Yes, so the desired digit should be reduced by that many (512 - 9).
Is the number of 2 digit numbers (90) lower than the desired digit (503 now)?
Yes, so the desired digit should be reduced by that many (503 - 90).
Is the number of 3 digit numbers (900) lower than the desired digit(413 now)?
No, so the desired digit is one of the digits of a 3 digit number.
413 / 3 is 137 (rounded down), so it's one of the digits of the 137th 3 digit numbers (so 237).
413 % 3 (modulo) is 2, so it's the 2nd digit, so it's supposed to be 3.
There can be miscalculations in this, but the overall logic should not be far.
Edit: you could also use a generator, but this can increase the runtime for big numbers
function getNthDigit() {
for ($i = 0;; ++$i) { // Start with 0, which is the 0-th digit
foreach (str_split((string)$i) as $digit) {
yield $digit;
}
}
}
$desiredDigit = 512;
foreach (getNthDigit() as $number => $digit) {
if ($number == $desiredDigit) {
break;
}
}
// $digit should be the desired digit
<?php
function getDigit($Nth){
if($Nth < 10) return $Nth;
$no_of_digits = 1;
$current_contribution = 9;
$actual_length = 9;
$prev_length = 0;
$starting_number = 1;
$power_of_10 = 1;
while($actual_length < $Nth){
$no_of_digits++;
$current_contribution *= 10;
$prev_length = $actual_length;
$actual_length += ($current_contribution * $no_of_digits);
$power_of_10 *= 10;
$starting_number *= 10;
}
$Nth = $Nth - $prev_length;
$offset = $Nth % $no_of_digits === 0 ? intval($Nth / $no_of_digits) - 1 : intval($Nth / $no_of_digits);
$number = strval($starting_number + $offset);
for($i=1;$i<=$no_of_digits;++$i){
if(($Nth - $i) % $no_of_digits === 0){
return $number[$i-1];
}
}
}
// first 100 Digits
for($i=1;$i<=100;++$i){
echo getDigit($i),PHP_EOL;
}
Demo: https://3v4l.org/3l0I7
Algorithm:
To find the nth digit, we will first find the number and then which digit of that number to choose as an answer.
Find the number:
If we carefully observe, the series increases in a sequential manner, such as shown in the table.
Table:
| Digits| Total numbers(of current digit)| Total Digits | Total digits of whole string |
|-------|--------------------------------|--------------|-------------------------------|
| 1 | 9 | 9 | 9 |
| 2 | 90 | 180 | 189 |
| 3 | 900 | 2700 | 2889 |
| 4 | 9000 | 36000 | 38889 |
The above table shows us that if we want to find, let's say 500th digit, then it's some digit of 3 digit number. If we go for 17th digit, then it's some digit of a 2 digit number and so on.
Now, let's take 200th digit as an example. Since it's less than 2889 and greater than 189, it's from a 3 digit number.
What we would do is breakdown the 200 into a smaller number such as 200 - 189 = 11. This 11 means that it's 11th digit of some 3 digit number which started with initial 3 digit number of 100(the starting number for 3 digit).
Now, we do 11 / 3(where 3 is number of digits) and get the quotient as 3. This 3 means that it's 3 numbers past the starting number 100, which we can say as 100 + 3 = 103(since it's 100,101,102 and then the 4th one as 103).
Now, we came to know that the number is 103. All is left to find out is which digit from 103.
Note that sometimes we come across a corner case of even divisibility such as 12 / 3. In this case, we subtract 1 from the quotient since our series of 3 digits starts from 100 and not 101( and so on and so forth for other digits).
Find out the digit:
Now, we know that the number is 103 for a 200 th digit( a.k.a 11 as we calculated above). To find out which one, we write down numbers of 3 digits in sequence and closely observe them.
Sequence:
1 0 0 1 0 1 1 0 2 1 0 3 1 0 4 1 0 5 1 0 6
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
If you observe, you can understand that the most MSB digit follows a sequence of 1,4,7,10,13 etc. Second most MSB follows a sequence of 2,5,8,11,14 etc and the last MSB(which is LSB) follows a sequence of 3,6,9,12,15 etc.
So, from th above sequence, it's pretty evident that 11(which we got after breaking down 200 initially) belongs to a sequence of the 2nd most MSB digit.
So, the final answer from 103 is 0 (the 2nd digit from left).
$num = '12345678910111213141516';
echo $num[16];
Result: 3
I've got a complex directions URL and embed URL that I would like to get polylines for. Once I can get them into polylines or something similar I can convert to final format: GeoJSON.
Direction Link
-or-
Embed Link
I have looked at the API's and I can't find anything that accepts or would decode the PB (what is this? it's not a protocol buffer). So far this is as far as I've got:
//php
$pb_array = explode('!', $pb);
foreach($pb_array as $key => $value){
echo "$key - $value<br/>";
}
===
1 - 1m73
2 - 1m12
3 - 1m3
4 - 1d1472548.9575794793
5 - 2d-72.8191002664707
6 - 3d43.87505426780168
7 - 2m3
8 - 1f0
9 - 2f0
10 - 3f0
11 - 3m2
12 - 1i1024
13 - 2i768
14 - 4f13.1
15 - 4m58
16 - 3e0
17 - 4m5
18 - 1s0x0%3A0xa58b3d6041ba69f8
19 - 2sGuilford+Welcome+Center
20 - 3m2
21 - 1d42.8120069
22 - 2d-72.56614689999999
23 - 4m3
24 - 3m2
25 - 1d43.3893165
26 - 2d-72.40772249999999
27 - 4m5
28 - 1s0x4cb52e78df455c83%3A0xb6946ec850907db8
29 - 2s130+Lower+Michigan+Road%2C+Pittsfield%2C+VT+05762
30 - 3m2
31 - 1d43.76898
32 - 2d-72.815214
33 - 4m4
34 - 1s0x0%3A0xea2de48bba82cc86
35 - 3m2
36 - 1d44.042544
37 - 2d-72.6046997
38 - 4m5
39 - 1s0x0%3A0x6bb602ed58bf4413
40 - 2sJay+Peak+Resort
41 - 3m2
42 - 1d44.9379515
43 - 2d-72.5045433
44 - 4m5
45 - 1s0x4cb392aaa4333a07%3A0x160aef1559868340
46 - 2sDolly+Copp+Campground+Rd%2C+Gorham%2C+NH+03581
47 - 3m2
48 - 1d44.335842199999995
49 - 2d-71.21837339999999
50 - 4m5
51 - 1s0x4cb392684201a94d%3A0xfa4a6f490a05429d
52 - 2sMt+Washington+Auto+Road%2C+1+Mount+Washington+Auto+Road%2C+Gorham%2C+NH+03581
53 - 3m2
54 - 1d44.288384099999995
55 - 2d-71.22459599999999
56 - 4m5
57 - 1s0x4cb38e798f42c3d9%3A0xc3b88e4dac01db12
58 - 2sMt+Washington
59 - 3m2
60 - 1d44.270585399999995
61 - 2d-71.3032723
62 - 4m5
63 - 1s0x89e2a7fa444124d5%3A0xe3ed24b6f864eba0
64 - 2sWells%2C+ME
65 - 3m2
66 - 1d43.322232899999996
67 - 2d-70.5805209
68 - 4m5
69 - 1s0x89e2ba813e828c71%3A0x8cdf74380f6a933d
70 - 2sLibby's+Oceanside+Camp%2C+York+Street%2C+York%2C+ME
71 - 3m2
72 - 1d43.147162
73 - 2d-70.626173
74 - 5e1
75 - 3m2
76 - 1sen
77 - 2sus
78 - 4v1472497940601
The closest hints I could find are from this thread. I will keep looking but I'm stuck.
I'm trying to create an API based solution that has an input of one of these URL's and returns a GeoJSON.
would decode the PB (what is this? it's not a protocol buffer)
For the record, because this overflow question keeps popping up on google results: it is a protocol buffer. PB litteraly stands for protocol buffer.
It's just a different ASCII encoding (a compact URL encoding reminiscent of the binary encoding, not the usual JSON-like text encoding. When you squint at it it's not that much different than torrent's structure encoding), and Google doesn't provide us the .proto file.
For each field:
first character is the id (identifies the field according to the corresponding .proto file)
second character is the type of the field
m is for message
s is for string
i, j, u, v are for various type of ints
f, d are for floating points
e is for enum
the rest is the payload
So to unpack the fields you're seeing (even if we don't have the .proto file):
1m73 message of type 1, containing 73 elements (the whole message set)
1m12 submessage of type 1, contains 12 elements (probably information about the view box in the map box)
1m3 sub-sub-message type 1, contains 3 elements (probably map coordinates)
1d1472548.9575794793 first double field (probably zoom level)
2d-72.8191002664707 second double field (probably longitude)
3d43.87505426780168 third double field (probably latitude)
2m3 second sub-sub-sub message (no idea given that it's not filled. Maybe a starting point if you code a route instead of a single point ?)
1f0, 2f0, 3f0 the three members, currently just zero
3m2 third block (looks like a screen resolution)
1i1024, 2i768 : 1024x768 ? (and probably the omited field 3 would have been the color depth if present ??)
4f13.1 no idea, but it's a float
4m58 next message with 58 elements (to me it looks like a bunch of POI that we need to display in the box)
3e0 an enum, set to zero (this one would be completely impossible to interpret without a proto or without experimenting, as you need the list of enums)
4m5 five more elements probably a map poi
- 1s0x0%3A0xa58b3d6041ba69f8 string '0x0:0xa58b3d6041ba69f8', note the use of Url_encoded character. In turn it looks like a pair of hex numbers, maybe a GUID ?
- 2sGuilford+Welcome+Center string, the name with plus instead of blank (like most URLs)
- 3m2 two elements to come
- 1d42.8120069 and 2d-72.56614689999999 doubles probably map coordinates
4m3 again a message of type 4 in this level, so probably another poi
- 3m2, 1d43.3893165, 2d-72.40772249999999 but this one only specifies coordinates, and nothing else
4m5 another poi
- 1s0x4cb52e78df455c83%3A0xb6946ec850907db8 different pair of hex, GUID
...you got the idea...
5e1 another bunch of information probably general settings
3m2 this setting is a message (and looks like a locale)
1sen, 2sus locale is en_US
4v1472497940601 some other large number...
Note: the original proto that Google doesn't show us, is probably a single multi level structure. Thus, the sub-sub-message ID don't have always the same meaning: they aren't global ID, but ID within the parent message.
inside a sub message ID 1 (view box ?), the sub-sub message 3 seems to be resolution.
inside a sub message ID 4 (POIs ?), the sub-ID 3 isn't even a message but some enum
inside a sub message ID 5 (parameters), the sub-sub message 3 is a locale
Well, here's my sloppy but working solution. My needs required GeoJSON, but others can use the google maps service to get the desired output once you have the lat/lng array.
$embed = '<iframe src="https://www.google.com/maps/embed?pb=!1m73!1m12!1m3!1d1472548.9575794793!2d-72.8191002664707!3d43.87505426780168!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!4m58!3e0!4m5!1s0x0%3A0xa58b3d6041ba69f8!2sGuilford+Welcome+Center!3m2!1d42.8120069!2d-72.56614689999999!4m3!3m2!1d43.3893165!2d-72.40772249999999!4m5!1s0x4cb52e78df455c83%3A0xb6946ec850907db8!2s130+Lower+Michigan+Road%2C+Pittsfield%2C+VT+05762!3m2!1d43.76898!2d-72.815214!4m4!1s0x0%3A0xea2de48bba82cc86!3m2!1d44.042544!2d-72.6046997!4m5!1s0x0%3A0x6bb602ed58bf4413!2sJay+Peak+Resort!3m2!1d44.9379515!2d-72.5045433!4m5!1s0x4cb392aaa4333a07%3A0x160aef1559868340!2sDolly+Copp+Campground+Rd%2C+Gorham%2C+NH+03581!3m2!1d44.335842199999995!2d-71.21837339999999!4m5!1s0x4cb392684201a94d%3A0xfa4a6f490a05429d!2sMt+Washington+Auto+Road%2C+1+Mount+Washington+Auto+Road%2C+Gorham%2C+NH+03581!3m2!1d44.288384099999995!2d-71.22459599999999!4m5!1s0x4cb38e798f42c3d9%3A0xc3b88e4dac01db12!2sMt+Washington!3m2!1d44.270585399999995!2d-71.3032723!4m5!1s0x89e2a7fa444124d5%3A0xe3ed24b6f864eba0!2sWells%2C+ME!3m2!1d43.322232899999996!2d-70.5805209!4m5!1s0x89e2ba813e828c71%3A0x8cdf74380f6a933d!2sLibby's+Oceanside+Camp%2C+York+Street%2C+York%2C+ME!3m2!1d43.147162!2d-70.626173!5e1!3m2!1sen!2sus!4v1472497940601" width="600" height="450" frameborder="0" style="border:0" allowfullscreen></iframe>';
$array = array();
preg_match( '/src="([^"]*)"/i', $embed, $array ) ;
list($pre, $pb) = split("pb=", $array[1]);
if($pb == "" || strpos($pb, "!") === false)
die(json_encode(array("success"=>false)));
//echo "PB Extracted:<br>";
//echo $pb;
///echo "<br><br>Decode:<br/>";
$pb_array = explode('!', $pb);
$coords = array();
$address;$addressHex;
$results = array();
foreach($pb_array as $key => $value){
//uncomment to debug output
//echo "$key - $value<br/>";
if($value == "3m2" || $value == "2m2"){
//3m2 seems to be the divider of these 'places'
if(count($coords) != 3) //don't add the center of map data (3 coordinates [height, lng, lat])
array_push($results, array("coords"=>$coords,"address"=>$address,"addressHex"=>$addressHex));
$coords = array(); //reset array
}else{
$type = substr($value, 1, 1);
$stype = substr($value, 0, 2);
$value = substr($value, 2);
//echo "$type - $value<br/>";
if($type == "d"){
//Found Lat,Lng
array_push($coords, $value);
}else if($stype == "2s"){
//Address
$address = $value;
}else if($stype == "1s"){
//Address Encoded in some way
$addressHex = $value;
}
}
}
//echo "<br><br>Google Result<br/>";
//echo json_encode($results);
//echo "<br><br>Mapbox API:<br/>";
$waypoints = array();
for($i=0;$i<count($results);$i++){
if(count($results[$i]["coords"])){
$lat = $results[$i]["coords"][0];
$lng = $results[$i]["coords"][1];
array_push($waypoints, "$lng%2C$lat");
}
}
$waypoints = implode("%3B", $waypoints); //convert to string
$mapbox_api_key = "pk.eyJ1I.....";
$url = "https://api.mapbox.com/directions/v5/mapbox/driving/$waypoints.json?steps=false&alternatives=false&overview=full&geometries=geojson&access_token=$mapbox_api_key";
//echo "<br><br>Mapbox Response:<br/>";
$response = file_get_contents($url);
$json = json_decode($response,true);
//echo "<br><br>Mapbox Geometry:<br/>";
$coordinates = $json["routes"][0]["geometry"]["coordinates"];
$geojson = (array("type"=>"FeatureCollection","features"=>array(array("type"=>"Feature","geometry"=>array("type"=>"LineString","coordinates"=>$coordinates),"properties"=>array()))));
echo json_encode(array("success"=>true, "geojson"=>$geojson));
i have a number of minutes as ceiling and tasks that demand time in minutes, im doing a while loop to sum the time required by the tasks until reach the ceiling, but im having a problem with one step in the loop, the first number is the loop, the second the task required time, the third is my ceiling. I must reset the the task_required_time variable before or once it reach the ceiling. Using
if ($task_required_time > $ceiling) {task_required_time = 0}
it reset after its over the ceiling:
1 - 120 - 2400
2 - 304 - 2400
3 - 424 - 2400
4 - 2092 - 2400
5 - 2212 - 2400
6 - 3580 - 2400 <---- here is when it reset as expected but should be in the step before.
7 - 120 - 2400
8 - 330 - 2400
9 - 450 - 2400
10 - 570 - 2400
I will appreciate some light on it.
You need to make the compare at the begining of the code. this may help:
while ($rows = mysql_fetch_array($duedates)) {
if ($tiempo_para_mix + (($rows['tiempo_reproduccion'])*2)+($tiempo_tqc_final*60) > $tiempo_efectivo) {
$tiempo_para_mix = 0;
};
$tiempo_para_mix += (($rows['tiempo_reproduccion'])*2)+($tiempo_tqc_final*60);
echo $x . " - " . $tiempo_para_mix . " - " . $tiempo_efectivo . "</br>";
$x++;
}
Can you please explain how this line of code is equivalent to the next code:
<?php
$string = chr( ( $number >> 6 ) + 192 ).chr( ( $number & 63 ) + 128 );
?>
Its equivalent to :
if ( $number >=128 && $number <=2047 ){
$byte1 = 192 + (int)($number / 64); //= 192 + ( $number >> 6 )
$byte2 = 128 + ($number % 64); //= 128 + ( $number & 63 )
$utf = chr($byte1).chr($byte2);
}
for example entering number 1989 both produces ߅
These codes are used for converting UNICODE Entities back to original UTF-8 characters.
The code on top uses binary operators.
>> is right shift operator. It shifts the bit in the number to the right (towards more significant bits).
So 11110000 >> 2 = 00111100
It's equivalent to division by powers of 2
$number >> $n is the same as $number / pow(2,$n).
The & is the "bitwise and" operator. It compares respective bits on both numbers, and sets in result those, that are 1 in both numbers.
11110000 & 01010101 = 01010000
By and'ing $number with 63 (001111111) you get the remainder of dividing $number by 64 (aka the modulus), which is written $number % 64.
$number >> 6 is a binary shift-right operation, ie: 11000000 >> 6 == 00000011 equivalent to $number / pow(2,6) aka $number / 64
$number & 63 is a binary AND with 00111111
Both are much faster to do as binary operations since they deal with powers or two.
Adding to #Mchl's answer the reason for adding 192 in UTF sequence is to signal the start of byte information
192 - 11000000 - Start of 2 Byte sequence ( 128 + 64)
224 - 11100000 - Start of 3 Byte sequence ( 128 + 64 + 32)
240 - 11110000 - Start of 4 Byte sequence ( 128 + 64 + 32 + 16)
248 - 11111000 - Start of 5 Byte sequence (Restricted) (... + 8)
252 - 11111100 - Start of 6 Byte sequence (Restricted) (... + 4)
254 - 11111110 - Invalid
Table Reference : https://en.wikipedia.org/w/index.php?title=UTF-8&oldid=388157043
UTF-8 byte range table