I'm having problems trying to "print" a PHP function to convert an IP address range to CIDR format, here is the function posted by IP2Location.com :
https://www.ip2location.com/tutorials/how-to-convert-ip-address-range-into-cidr
function iprange2cidr($ipStart, $ipEnd){
if (is_string($ipStart) || is_string($ipEnd)){
$start = ip2long($ipStart);
$end = ip2long($ipEnd);
}
else{
$start = $ipStart;
$end = $ipEnd;
}
$result = array();
while($end >= $start){
$maxSize = 32;
while ($maxSize > 0){
$mask = hexdec(iMask($maxSize - 1));
$maskBase = $start & $mask;
if($maskBase != $start) break;
$maxSize--;
}
$x = log($end - $start + 1)/log(2);
$maxDiff = floor(32 - floor($x));
if($maxSize < $maxDiff){
$maxSize = $maxDiff;
}
$ip = long2ip($start);
array_push($result, "$ip/$maxSize");
$start += pow(2, (32-$maxSize));
}
return $result;
}
function iMask($s){
return base_convert((pow(2, 32) - pow(2, (32-$s))), 10, 16);
}
(note: corrected 'echo' to 'return' result)
I've tried all of the suggested ways of "feeding" the $ipStart and $ipEnd values to the function, and also to "echo" or "print" the resulting array, but all I get is the word "Array".
For example, after the function is defined, I try:
$ipStart = '8.8.8.8';
$ipEnd = '8.8.8.254';
echo iprange2cidr($ipStart, $ipEnd);
... I appologise for the novice question, I'm a PHP newbie. I'm just not sure how to use the function. Any guidance on what I'm doing wrong would be appreciated! My server uses PHP 7.1. Thank you.
Let's return $result instead.
function iprange2cidr($ipStart, $ipEnd){
....
return $result;
}
Then let's convert it to a string before we echo it:
$ipStart = '8.8.8.8';
$ipEnd = '8.8.8.254';
$range = iprange2cidr($ipStart, $ipEnd);
echo implode("\n",$range);
You can use print_r($result); to get human-readable output.
see doc for more info.
proper way of using function is to return value like
function iprange2cidr($ipStart, $ipEnd){
....
return $result;}
and then call the function like
$returnedVale = iprange2cidr($ipStart, $ipEnd);
$returnedVale = iprange2cidr($ipStart, $ipEnd);
echo"<pre>";print_r($returnedVale);echo"</pre>";
Related
Here is my model function for generate serial numbers
public function getmax($field_name,$table_name){
$this->db->select_max($field_name);
$res1 = $this->db->get($table_name);
if ($res1->num_rows() > 0) {
$res2 = $res1->result_array();
}
$max = $res2[0][$field_name];
if($max == NULL) return 1; else return $max+1;
}
Here is my controller Function
$CardNo = $this->general_model->getmax('card_number','digicardusers');
I want to set serial numbers starting from 00000000001.How to change the code to get 11 digit serial numbers.Any one please help
Presuming your just looking for the 0'padding, use sprintf()
<?php
for ($i = 1; $i < 25; $i++) {
echo sprintf("%'.011d", $i).PHP_EOL;
}
https://3v4l.org/UanaJ
00000000001
00000000002
00000000003
00000000004
00000000005
00000000006
00000000007
00000000008
00000000009
00000000010
00000000011
...
you can use this function just pass param $digit
function randomXDigit($digits = 11) {
return str_pad(rand(0, pow(10, $digits)-1), $digits, '0', STR_PAD_LEFT);
}
IP2Location.com has a working PHP function to convert a SINGLE IP range to CIDR format. I want to periodically feed a LIST of IP ranges (an array?) through the function to get a list of CIDR formatted results. I'm not sure how to do that properly with PHP, and perhaps it's the wrong tool? Any guidance appreciated. Here is the function, with sample input/output below:
function iprange2cidr($ipStart, $ipEnd){
if (is_string($ipStart) || is_string($ipEnd)){
$start = ip2long($ipStart);
$end = ip2long($ipEnd);
}
else{
$start = $ipStart;
$end = $ipEnd;
}
$result = array();
while($end >= $start){
$maxSize = 32;
while ($maxSize > 0){
$mask = hexdec(iMask($maxSize - 1));
$maskBase = $start & $mask;
if($maskBase != $start) break;
$maxSize--;
}
$x = log($end - $start + 1)/log(2);
$maxDiff = floor(32 - floor($x));
if($maxSize < $maxDiff){
$maxSize = $maxDiff;
}
$ip = long2ip($start);
array_push($result, "$ip/$maxSize");
$start += pow(2, (32-$maxSize));
}
return $result;
}
function iMask($s){
return base_convert((pow(2, 32) - pow(2, (32-$s))), 10, 16);
}
Then to test the function, supplying a single range with ipStart of 8.8.8.0 and ipEnd of 8.8.8.16, the CIDR result of the function is an array, echoed using implode:
$ipStart = '8.8.8.0';
$ipEnd = '8.8.8.16';
$ipCidr = iprange2cidr($ipStart, $ipEnd);
echo implode ("<br>", $ipCidr);
The CIDR formatted result is:
8.8.8.0/28
8.8.8.16/32
That works well for a single range. How would you suggest feeding a list of ranges to the ipStart and ipEnd variables, and have the function run through the list, building a final result list?
Just loop through the list of ranges, and use array_merge() to append the results to the collection of all results.
$ranges = [
["start" => "8.8.8.0", "end" => "8.8.8.16"],
["start" => "192.168.10.5", "end" => "192.168.32.255"],
["start" => "10.1.2.32", "end" => "10.1.3.0"]
];
$allCidrs = [];
foreach ($ranges as $range) {
$cidr = iprange2cidr($range["start"], $range["end"]);
$allCidrs = array_merge($allCidrs, $cidr);
}
I've created a memoized function of the recursive version of fibonacci.
I use this as an example for other kinds of functions that would use memoization.
My implementation is bad since if I include it in a library, that means that the global variable is still seen..
This is the original recursive fibonacci function:
function fibonacci($n) {
if($n > 1) {
return fibonacci($n-1) + fibonacci($n-2);
}
return $n;
}
and I modified it to a memoized version:
$memo = array();
function fibonacciMemo($n) {
global $memo;
if(array_key_exists($n, $memo)) {
return $memo[$n];
}
else {
if($n > 1) {
$result = fibonacciMemo($n-1) + fibonacciMemo($n-2);
$memo[$n] = $result;
return $result;
}
return $n;
}
}
I purposely didn't use the iterative method in implementing fibonacci.
Is there any better ways to memoize fibonacci function in php? Can you suggest me better improvements? I've seen func_get_args() and call_user_func_array as another way but I can't seem to know what is better?
So my main question is: How can I memoize fibonacci function in php properly? or What is the best way in memoizing fibonacci function in php?
Well, Edd Mann shows an excellent way to implement a memoize function in php in His post
Here is the example code (actually taken from Edd Mann's post):
$memoize = function($func)
{
return function() use ($func)
{
static $cache = [];
$args = func_get_args();
$key = md5(serialize($args));
if ( ! isset($cache[$key])) {
$cache[$key] = call_user_func_array($func, $args);
}
return $cache[$key];
};
};
$fibonacci = $memoize(function($n) use (&$fibonacci)
{
return ($n < 2) ? $n : $fibonacci($n - 1) + $fibonacci($n - 2);
});
Notice that the global definition it's replaced thanks to function clousure and PHP's first-class function support.
Other solution:
You can create a class containing as static members: fibonnacciMemo and $memo. Notice that you don't longer have to use $memo as a global variable, so it won't give any conflict with other namespaces.
Here is the example:
class Fib{
//$memo and fibonacciMemo are static members
static $memo = array();
static function fibonacciMemo($n) {
if(array_key_exists($n, static::$memo)) {
return static::$memo[$n];
}
else {
if($n > 1) {
$result = static::fibonacciMemo($n-1) + static::fibonacciMemo($n-2);
static::$memo[$n] = $result;
return $result;
}
return $n;
}
}
}
//Using the same method by Edd Mann to benchmark
//the results
$start = microtime(true);
Fib::fibonacciMemo(10);
echo sprintf("%f\n", microtime(true) - $start);
//outputs 0.000249
$start = microtime(true);
Fib::fibonacciMemo(10);
echo sprintf("%f\n", microtime(true) - $start);
//outputs 0.000016 (now with memoized fibonacci)
//Cleaning $memo
Fib::$memo = array();
$start = microtime(true);
Fib::fibonacciMemo(10);
echo sprintf("%f\n", microtime(true) - $start);
//outputs 0.000203 (after 'cleaning' $memo)
Using this, you avoid the use of global and also the problem of cleaning the cache. Althought, $memo is not thread save and the keys stored are no hashed values.
Anyways, you can use all the php memoize utilites such as memoize-php
i think... this should to to memoize a fibonacci:
function fib($n, &$computed = array(0,1)) {
if (!array_key_exists($n,$computed)) {
$computed[$n] = fib($n-1, $computed) + fib($n-2, $computed);
}
return $computed[$n];
}
some test
$arr = array(0,1);
$start = microtime(true);
fib(10,$arr);
echo sprintf("%f\n", microtime(true) - $start);
//0.000068
$start = microtime(true);
fib(10,$arr);
echo sprintf("%f\n", microtime(true) - $start);
//0.000005
//Cleaning $arr
$arr = array(0,1);
$start = microtime(true);
fib(10,$arr);
echo sprintf("%f\n", microtime(true) - $start);
//0.000039
Another solution:
function fib($n, &$memo = []) {
if (array_key_exists($n,$memo)) {
return $memo[$n];
}
if ($n <=2 ){
return 1;
}
$memo[$n] = fib($n-1, $memo) + fib($n-2, $memo);
return $memo[$n];
}
Performance:
$start = microtime(true);
fib(100);
echo sprintf("%f\n", microtime(true) - $start);
// 0.000041
This's an implementation of memoize a fibonacci:
function fib(int $n, array &$memo = [0,1,1]) : float {
return $memo[$n] ?? $memo[$n] = fib($n-1, $memo) + fib($n-2, $memo);
}
Call
echo fib(20); // 6765
function fibMemo($n)
{
static $cache = [];
//print_r($cache);
if (!empty($cache[$n])) {
return $cache[$n];
} else {
if ($n < 2) {
return $n;
} else {
$p = fibMemo($n - 1) + fibMemo($n - 2);
$cache[$n] = $p;
return $p;
}
}
}
echo fibMemo(250);
I have a script which calls this function more than 100k times, so I am looking for anyway to squeeze a bit more performance out of it.
Can you suggest optimisations or an alternate method for calculating standard deviation in PHP?
function calcStandardDev($samples){
$sample_count = count($samples);
for ($current_sample = 0; $sample_count > $current_sample; ++$current_sample) $sample_square[$current_sample] = pow($samples[$current_sample], 2);
return sqrt(array_sum($sample_square) / $sample_count - pow((array_sum($samples) / $sample_count), 2));
}
$samples[$current_sample] * $samples[$current_sample]
is going to be faster than
pow($samples[$current_sample], 2)
because it doesn't have the overhead of the function call.
Then you can also simplify
pow((array_sum($samples) / $sample_count), 2));
to prevent calling the pow() function again
To avoid array_sum($samples) being called twice as a result of that change, calculate it once and store to a var before the loop, then just reference that var in the formula.
EDIT
function calcStandardDev($samples){
$sample_count = count($samples);
$sumSamples = array_sum($samples);
for ($current_sample = 0; $sample_count > $current_sample; ++$current_sample)
$sample_square[$current_sample] = $samples[$current_sample] * $samples[$current_sample];
return sqrt(array_sum($sample_square) / $sample_count - ( ($sumSamples / $sample_count) *
($sumSamples / $sample_count)
)
);
}
foreach by referance is faster than for, an you already have a loop, you can calculate "sum" in this loop. and $x*$x is so faster then pow($x,2);
there are some functions comparations. hope to help.
Your Function microtime = ~ 0.526
Second Function = ~ 0.290
<?php
function calcStandardDev($samples)
{
$sample_count = count($samples);
for ($current_sample = 0; $sample_count > $current_sample; ++$current_sample)
$sample_square[$current_sample] = pow($samples[$current_sample], 2);
return sqrt(array_sum($sample_square) / $sample_count - pow((array_sum($samples) / $sample_count), 2));
}
function calcStandardDev2($samples)
{
$sample_count = count($samples);
$sum_sample_square = 0;
$sum_sample = 0;
foreach ($samples as &$sample)
{
$sum_sample += $sample;
$sum_sample_square += $sample * $sample;
}
return sqrt($sum_sample_square / $sample_count - pow($sum_sample / $sample_count,2));
}
function calcStandardDev3($samples)
{
$sample_count = count($samples);
$sum_sample_square = 0;
$sum_sample = 0;
foreach ($samples as &$sample)
{
$sum_sample += $sample;
$sum_sample_square += pow($sample ,2);
}
return sqrt($sum_sample_square / $sample_count - pow($sum_sample / $sample_count,2));
}
echo "<pre>";
$samples = range(2,100000);
$start = microtime(true);
echo calcStandardDev($samples)."\r\n";
$end = microtime(true);
echo $end - $start ."\r\n";
echo "-------\r\n";
$start = microtime(true);
echo calcStandardDev2($samples)."\r\n";
$end = microtime(true);
echo $end - $start."\r\n";
echo "-------\r\n";
$start = microtime(true);
echo calcStandardDev3($samples)."\r\n";
$end = microtime(true);
echo $end - $start;
echo "-------\r\n";
?>
Replace both call to array_sum by calculating the respective values yourself. That way you just walk through your array one time instead of three times.
function calcStandardDev($samples){
$sample_count = count($samples);
$sum = 0;
$sum_sqaure = 0;
for ($current_sample = 0; $sample_count > $current_sample; ++$current_sample) {
$sum_square += pow($samples[$current_sample], 2);
$sum += $samples[$current_sample];
}
return sqrt( $sum_square / $sample_count - pow( $sum / $sample_count, 2));
}
Im working with a php url shortener and my problem is that it only creates the MAX number of shortening codes up to 2 characters (eg domain.com/XX). I want it to go up to 5 characters (eg domain.com/XXXXX)
I believe i found the relevant code, but im not sure how to change it to allow for this modification
function decode_url_id($code)
{
$scheme = "abcdefghijklmnoprstuqwxvyz0123456789ABCDEFGHIJKLMNOPRSTQWXUVYZ";
$scheme_size = strlen($scheme);
$number = 0;
$code_size = strlen($code);
$code = strrev($code);
for($i = 0; $i < $code_size; $i++)
{
$digit_value = strpos($scheme, $code[$i]);
$number += ($digit_value * pow($scheme_size, $i));
}
return $number;
}
function encode_url_id($number, $code="")
{
$scheme = "abcdefghijklmnoprstuqwxvyz0123456789ABCDEFGHIJKLMNOPRSTQWXUVYZ";
$scheme_size = strlen($scheme);
if ($number >= $scheme_size)
{
$c = $number % $scheme_size;
$code .= $scheme[$c];
$number = floor($number / $scheme_size);
return encode_url_id($number, $code);
}
else
{
$code .= $scheme[$number];
$code = strrev($code);
}
return $code;
}
Am i barking up the wrong tree?
Why not just encode the ID of the URL in the database with http://www.pgregg.com/projects/php/base_conversion/base_conversion.inc.phps.
Example usage:
$new_url = base_base2base($link_id, 10, 62);