Convert VB6 code to PHP - php

I want to convert Visual Basic 6 Code to PHP Code. I am new to PHP please help me to convert my VB6 Code to PHP. So far I tried to convert this into php code when I tried the code there is an error in the "
CryptRC4 = CryptRC4 & Chr$((pvCryptXor(baS((CLng(baS(li)) + baS(lJ)) Mod 256), Asc(Mid$(sText, lIdx, 1)))));
part and also I don't know how to proceed to the sub functions. Please see the codes below. The vb code is used to encrypt strings. I want to convert it to php format.
PHP Code
<?php
function CryptRC4($sText,$sKey){
$baS = 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,158,159,
160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,
176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,
192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,
208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,
224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,
240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255);
$baK = 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,158,159,
160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,
176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,
192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,
208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,
224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,
240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255);
$bytSwap = 0;
$li = 0;
$lJ = 0;
$lIdx = 0;
for( $lIdx = 0; $lIdx < 256; $lIdx++){
$baS[$lIdx] = $lIdx;
$baK[$lIdx] = ord(substr($sKey, 1 + ($lIdx % strlen($sKey)), 1));
}
for($li = 0; $li < 256; $li++){
$lJ = ($baS[$li] + $baK[$li]) % 256;
$bytSwap = $baS[$li];
$baS[$li] = $baS[$lJ];
$baS[$lJ] = $bytSwap;
}
$li = 0;
$lJ = 0;
$data_str = "";
for($lIdx = 0; $lIdx < strlen($sText); $lIdx++){
$li = ($li + 1) % 256;
$lJ = ($lJ + $baS[$li]) % 256;
$bytSwap = $baS[$li];
$baS[$li] = $baS[$lJ];
$baS[$lJ] = $bytSwap;
#echo chr((pvCryptXor($baS[(round(($baS[$li]) + $baS[$lJ])) % 256], ord(substr($sText, $lIdx, 1)))));
$data_str .= chr((pvCryptXor($baS[(round(($baS[$li]) + $baS[$lJ])) % 256], ord(substr($sText, $lIdx, 1)))));
}
echo $data_str;
}
function pvCryptXor($li, $lJ){
if($li = $lJ){
$pcx = $lJ;
}
else {
$pcx = $li Xor $lJ;
}
return $pcx;
}
unction ToHexDump($sText) {
$lIdx;
for($lIdx = 1; $lIdx < strlen($sText); $lIdx++){
$thd .= Right$("0" & Hex(Asc(Mid(sText, lIdx, 1))), 2)
echo $thd;
}
return $thd;
}
FromHexDump("events");
function FromHexDump($sText) {
$fhd = "";
for($lIdx = 0; $lIdx < strlen($sText); $lIdx++){
$fhd .= chr(CLng("&H" & Mid(sText, lIdx, 2)));
}
return $fhd;
}
?>
VB Code:
Public Function CryptRC4(sText As String, sKey As String) As String
On Error Resume Next
Dim baS(0 To 255) As Byte
Dim baK(0 To 255) As Byte
Dim bytSwap As Byte
Dim li As Long
Dim lJ As Long
Dim lIdx As Long
For lIdx = 0 To 255
baS(lIdx) = lIdx
baK(lIdx) = Asc(Mid$(sKey, 1 + (lIdx Mod Len(sKey)), 1))
Next
For li = 0 To 255
lJ = (lJ + baS(li) + baK(li)) Mod 256
bytSwap = baS(li)
baS(li) = baS(lJ)
baS(lJ) = bytSwap
Next
li = 0
lJ = 0
For lIdx = 1 To Len(sText)
li = (li + 1) Mod 256
lJ = (lJ + baS(li)) Mod 256
bytSwap = baS(li)
baS(li) = baS(lJ)
baS(lJ) = bytSwap
CryptRC4 = CryptRC4 & Chr$((pvCryptXor(baS((CLng(baS(li)) + baS(lJ)) Mod 256), Asc(Mid$(sText, lIdx, 1)))))
Next
End Function
Private Function pvCryptXor(ByVal li As Long, ByVal lJ As Long) As Long
On Error Resume Next
If li = lJ Then
pvCryptXor = lJ
Else
pvCryptXor = li Xor lJ
End If
End Function
Public Function ToHexDump(sText As String) As String
On Error Resume Next
Dim lIdx As Long
For lIdx = 1 To Len(sText)
ToHexDump = ToHexDump & Right$("0" & Hex(Asc(Mid(sText, lIdx, 1))), 2)
Next
End Function
Public Function FromHexDump(sText As String) As String
On Error Resume Next
Dim lIdx As Long
For lIdx = 1 To Len(sText) Step 2
FromHexDump = FromHexDump & Chr$(CLng("&H" & Mid(sText, lIdx, 2)))
Next
End Function

I revised your updated code and it seems you only had a few minor errors in it, look and my changes:
I guess you can use the build in PHP function hex2bin and bin2hex instead fo you own hex conversion.
function CryptRC4($sText,$sKey){
$baS = range(0, 255); // you can use range instead of your manual arrays
$baK = range(0, 255);
$bytSwap = 0;
$li = 0;
$lJ = 0;
$lIdx = 0;
for( $lIdx = 0; $lIdx < 256; $lIdx++){
$baS[$lIdx] = $lIdx;
$baK[$lIdx] = ord(substr($sKey, 1 + ($lIdx % strlen($sKey)), 1));
}
for($li = 0; $li < 256; $li++){
$lJ = ($baS[$li] + $baK[$li]) % 256;
$bytSwap = $baS[$li];
$baS[$li] = $baS[$lJ];
$baS[$lJ] = $bytSwap;
}
$li = 0;
$lJ = 0;
$data_str = "";
for($lIdx = 0; $lIdx < strlen($sText); $lIdx++){
$li = ($li + 1) % 256;
$lJ = ($lJ + $baS[$li]) % 256;
$bytSwap = $baS[$li];
$baS[$li] = $baS[$lJ];
$baS[$lJ] = $bytSwap;
#echo chr((pvCryptXor($baS[(round(($baS[$li]) + $baS[$lJ])) % 256], ord(substr($sText, $lIdx, 1)))));
$data_str .= chr((pvCryptXor($baS[(round(($baS[$li]) + $baS[$lJ])) % 256], ord(substr($sText, $lIdx, 1)))));
}
return $data_str; // changed from echo to return
}
function pvCryptXor($li, $lJ){
if($li == $lJ){ // you had an error here, use == to compare instead of a single =
$pcx = $lJ;
}
else {
$pcx = $li ^ $lJ; // XOR function in PHP is the ^ operator
}
return $pcx;
}
$str_hex = bin2hex("events");
$str_enc = CryptRC4($str_hex,"password");
$str_dec = hex2bin(CryptRC4($str_enc,"password"));
echo $str_hex . PHP_EOL . $str_enc . PHP_EOL . $str_dec;
OUTPUT:
6576656e7473
'�����~i��
events
So it seems to me as it's actually encoding and decoding correctly!?

It seems the original VB6 implementation of CryptRC4 function is from my answer to "VB6 encrypt text using password" question on SO.
So let me try answering your Q with this short php implementation of all public functions in the VB6 snippet:
function CryptRC4($text, $key) {
return openssl_encrypt($text, "RC4-40", $key, 1 | 2);
}
function ToHexDump($text) {
return strtoupper(bin2hex($text));
}
function FromHexDump($text) {
return hex2bin($text);
}
You can excercise these one-liners with something like this:
$text = "a message here";
$password = "password";
$encr = ToHexDump(CryptRC4($text, $password));
$decr = CryptRC4(FromHexDump($encr), $password);
echo $text . PHP_EOL . $encr . PHP_EOL . $decr;

As it's intended for passwords, you can save yourself a lot of hassle. PHP has got built in functions (version 5.5 and newer) that are designed for dealing with the hashing of passwords and for verifying hashed passwords against the password submitted by a user. Have a read through the PHP relevant PHP manual pages http://php.net/manual/en/book.password.php

Related

How translate a neural network from C to PHP

I'm trying to translate this algorithm from C language to PHP (for study)
This is an example of a perceptron. I copied the example written in c and I'm trying to translate it into PHP. Currently I wrote this code, what am I wrong? As output I only know 101 iterations with result always 1.
This is the C program:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#define LEARNING_RATE 0.1
#define MAX_ITERATION 100
float randomFloat()
{
return (float)rand() / (float)RAND_MAX;
}
int calculateOutput(float weights[], float x, float y)
{
float sum = x * weights[0] + y * weights[1] + weights[2];
return (sum >= 0) ? 1 : -1;
}
int main(int argc, char *argv[])
{
srand(time(NULL));
float x[208], y[208], weights[3], localError, globalError;
int outputs[208], patternCount, i, p, iteration, output;
FILE *fp;
if ((fp = fopen("test1.txt", "r")) == NULL) {
printf("Cannot open file.\n");
exit(1);
}
i = 0;
while (fscanf(fp, "%f %f %d", &x[i], &y[i], &outputs[i]) != EOF) {
if (outputs[i] == 0) {
outputs[i] = -1;
}
i++;
}
patternCount = i;
weights[0] = randomFloat();
weights[1] = randomFloat();
weights[2] = randomFloat();
iteration = 0;
do {
iteration++;
globalError = 0;
for (p = 0; p < patternCount; p++) {
output = calculateOutput(weights, x[p], y[p]);
localError = outputs[p] - output;
weights[0] += LEARNING_RATE * localError * x[p];
weights[1] += LEARNING_RATE * localError * y[p];
weights[2] += LEARNING_RATE * localError;
globalError += (localError*localError);
}
/* Root Mean Squared Error */
printf("Iteration %d : RMSE = %.4f\n", iteration,
sqrt(globalError/patternCount));
} while (globalError != 0 && iteration<=MAX_ITERATION);
printf("\nDecision boundary (line) equation: %.2f*x + %.2f*y + %.2f = 0\n",
weights[0], weights[1], weights[2]);
return 0;
}
and this is the code that I wrote
<?php
define("LEARNING_RATE", 0.1);
define("MAX_ITERATION", 100);
function randomFloat(){ return (float) mt_rand() / mt_getrandmax(); }
function calculateOutput($weights, $x, $y){
$sum = (float) $x * $weights[0] + $y * $weights[1] + $weights[2];
return ($sum >= 0) ? 1 : -1;
}
srand(time());
$i = 0;
$ars = explode("\n",file_get_contents('https://raw.githubusercontent.com/RichardKnop/ansi-c-perceptron/master/test1.txt'));
foreach($ars as $ar){
$temp = explode("\t", $ar);
$x[$i] = (float) $temp[0];
$y[$i] = (float) $temp[1];
$output[$i] = (int) $temp[2];
if($output[$i] == 0)
$output[$i] = -1;
$i++;
}
$patternCount = $i;
$weights[0] = randomFloat();
$weights[1] = randomFloat();
$weights[2] = randomFloat();
$iteration = 0;
do{
$iteration++;
$globalError = 0;
for ($p = 0; $p < $patternCount; $p++) {
$output = calculateOutput($weights, $x[$p], $y[$p]);
$localError = $outputs[$p] - $output;
$weights[0] += LEARNING_RATE * $localError * $x[$p];
$weights[1] += LEARNING_RATE * $localError * $y[$p];
$weights[2] += LEARNING_RATE * $localError;
$globalError += ($localError*$localError);
}
$r .= "Iteration $iteration : RMSE = " .
sqrt($globalError/$patternCount)."<br>";
}while($globalError != 0 && $iteration<=MAX_ITERATION);
echo $r;
echo "<br><hr><br>";
echo "Decision boundary (line) equation: ".$weights[0]."*x + ".$weights[1]."*y + ".$weights[2]." = 0<br>";
it's practically identical, but why does it not work?
$ars = explode("\n",file_get_contents('…'));
Since the file ends with a \n, this yields an empty string as the last array value, which disrupts the foreach($ars as $ar) loop. To read the file into an array, simply use:
$ars = file('…');
In the foreach($ars as $ar) loop, you used the wrong name $output[$i] instead of $outputs[$i].
$r .= "Iteration $iteration : RMSE = " .
sqrt($globalError/$patternCount)."<br>";
}while($globalError != 0 && $iteration<=MAX_ITERATION);
echo $r;
You didn't initialize $r. Instead of the above, you can use:
echo "Iteration $iteration : RMSE = " .
sqrt($globalError/$patternCount)."<br>";
} while ($globalError != 0 && $iteration<=MAX_ITERATION);

CRC Maxim/Dallas 1Wire Generation: translate Visual Basic to PHP

i Need a function that generates the Maxim/Dallas 1-Wire CRC 8bit-Code like this page:
http://www.datastat.com/sysadminjournal/maximcrc.cgi
For that problem I found an little Excel Calculator for solution.
It works correctly, but I got the Problem to translate it into PHP language.
Original VB Code:
Private Sub ROMCRC_Click()
Dim InHex, OutBinStr As String
Dim OutBinArr(1 To 56) As Integer
Dim OutDec, i, CRC(1 To 8), CRCTemp As Integer
InHex = Range("ROMByte1").Value & Range("ROMByte2").Value & Range("ROMByte3").Value & Range("ROMByte4").Value & Range("ROMByte5").Value & Range("ROMByte6").Value & Range("ROMByte7").Value
OutBinStr = HexToBin(InHex)
' Convert string to array, LSB = OutBinArr(1)
For i = 1 To 56
OutBinArr(57 - i) = Mid$(OutBinStr, i, 1) ' Split(OutBinStr)
Next i
'Initialize CRC
For i = 1 To 8
CRC(i) = 0
Next i
'Calculate CRC
For i = 1 To 56
CRCTemp = CRC(1) Xor OutBinArr(i)
CRC(1) = CRC(2)
CRC(2) = CRC(3)
CRC(3) = CRC(4) Xor CRCTemp
CRC(4) = CRC(5) Xor CRCTemp
CRC(5) = CRC(6)
CRC(6) = CRC(7)
CRC(7) = CRC(8)
CRC(8) = CRCTemp
Next i
DecCRC = BinToDec(CRC)
Range("ROMCRCValue").Value = DecCRC
End Sub
Private Function HexToBin(hstr)
'convert hex string to binary string
cnvarr = Array("0000", "0001", "0010", "0011", _
"0100", "0101", "0110", "0111", "1000", _
"1001", "1010", "1011", "1100", "1101", _
"1110", "1111")
bstr = ""
For i = 1 To Len(hstr)
hdgt = Mid(hstr, i, 1)
cix = CInt("&H" & hdgt)
bstr = bstr & cnvarr(cix)
Next
HexToBin = bstr
End Function
Function BinToDec(bstr)
'convert 8 bit Binary number to Decimal
Dim j, Out As Integer
Out = 0
For j = 1 To 8
Out = Out + bstr(j) * 2 ^ (j - 1)
Next j
BinToDec = Out
End Function
My PHP test code:
protected function HexToBin($hstr) {
//convert hex string to binary string
$cnvarr = array(
'0000',
'0001',
'0010',
'0011',
'0100',
'0101',
'0110',
'0111',
'1000',
'1001',
'1010',
'1011',
'1100',
'1101',
'1110',
'1111'
);
$bstr = "";
for ($i = 1; $i <= strlen($hstr); $i++) {
$hdgt = substr($hstr, $i, 1);
$cix = intval($hdgt);
echo $cix.'|';
$bstr .= $cnvarr[$cix];
}
return $bstr;
}
protected function createHash($data) {
//$OutBinStr = $this->HexToBin($data);
$OutBinStr = hex2bin($data);
$OutBinArr = array();
$crc = array();
//Convert string to array, LSB = OutBinArr(1)
for ($i = 1; $i <= 56; $i++) {
$OutBinArr[57 - $i] = substr($OutBinStr, $i - 1, 1);
}
//initialize crc
for ($i = 1; $i <= 8; $i++) {
$crc[$i] = 0;
}
// calculate
for ($i = 1; $i <= 56; $i++) {
$CRCTemp = $crc[1] ^ $OutBinArr[$i];
$crc[1] = $crc[2];
$crc[2] = $crc[3];
$crc[3] = $crc[4] ^ $CRCTemp;
$crc[4] = $crc[5] ^ $CRCTemp;
$crc[5] = $crc[6];
$crc[6] = $crc[7];
$crc[7] = $crc[8];
$crc[8] = $CRCTemp;
}
return implode('', $crc);
}
Example call:
$buttonId = '0000145D6E0F01';
echo $this->createHash($buttonId);
I thank you if you have any Ideas why the Script does not generate the correct crc.
Thank you, nice regards
Michael
Your HexToBin() was generating wrong string. The for loop for substr() started with 1 instead of 0. See substr manual.
Imploding $crc resulted an reverse bit order value.
<?PHP
function HexToBin($hstr){
$hstr = str_replace(' ','',$hstr);
$hArr = str_split($hstr);
$bstr = "";
foreach($hArr AS $c){
$cix = sprintf("0x0{$c}");
// echo sprintf("%04b|",hexdec($cix));
$bstr .= sprintf("%04b",hexdec($cix));
}
return $bstr;
}
function createHash($data){
$OutBinStr = HexToBin($data);
$crc = array_fill(0,8,0);
$OutBinArr = array_reverse(str_split($OutBinStr));
// calculate
foreach($OutBinArr AS $i){
$CRCTemp = $crc[0] ^ $i;
$crc[0] = $crc[1];
$crc[1] = $crc[2];
$crc[2] = $crc[3] ^ $CRCTemp;
$crc[3] = $crc[4] ^ $CRCTemp;
$crc[4] = $crc[5];
$crc[5] = $crc[6];
$crc[6] = $crc[7];
$crc[7] = $CRCTemp;
}
$crc = array_reverse($crc);
return implode('', $crc);
}
$buttonId = '00 00 14 5D 6E 0F 01'; // 59 => 3B
// $buttonId = '12 AA 12 5F 14 A2 12 12'; // 109 => 6D
$crc = bindec(createHash($buttonId));
printf("\n%d => %X",$crc,$crc);
?>

Vigenere in PHP

could anyone help me fix this Vigenere cypher in PHP?
Sorry for the ripped up code, that's from where I have been dissecting it for hours - trying to fix!
Anyhow, the code outputs 'Ace' when it should output 'Abc'.
There is some weird double offset which I don't have the maths brain to fix! Thanks for reading.
The code originates from here in AutoHotkey script - I have attempted to transcribe it. There are PHP Vigenere examples on the web (although not on Rosetta Code, weirdly!).. but anyhow, this one is modified to accept lower case as well as the standard capitals. Thanks.
$key = "AAA";
$keyLength = 3;
$keyIndex = 0;
$messageAsArray[0] = "A";
$messageAsArray[1] = "b";
$messageAsArray[2] = "c";
foreach ($messageAsArray as $value) //Loop through input string array
{
$thisValueASCII = ord($value);
if ($thisValueASCII >= 65 && $thisValueASCII <= 90) //if is uppercase
{
$thisValueASCIIOffset = 65;
}
else //if is lowercase
{
$thisValueASCIIOffset = 97;
}
$thisA = $thisValueASCII - $thisValueASCIIOffset;
$thisB = fmod($keyIndex,$keyLength);
$thisC = substr($key, $thisB, 1);
$thisD = ord($thisC) - 65;
$thisE = $thisA + $thisD;
$thisF = fmod($thisE,26);
$thisG = $thisF + $thisValueASCII ;
$thisOutput = chr($thisG);
$output = $output . $thisOutput ;
$keyIndex++;
}
echo $output
Ok, I read your code.
You're encoding, and your error is quite simple :
$thisG = $thisF + $thisValueASCII ;
In this step, $thisF is your encrypted letter, which value is between 0 and 25. You want to print it as an ascii char and, instead of adding the offset, you're adding the uncrypted ascii value, which makes no sense.
You should have :
$thisG = $thisF + $thisValueASCIIOffset;
A few tips.
You don't need to have your text or key as an array, you can use it as if it was one.
You can use the % operator instead of fmod. Makes the code easier to read, but it is just a personnal preference.
For instance :
$key = "AAA";
$keyLength = strlen($key);
$keyIndex = 0;
$message = str_split("Abc");
$output = '';
foreach($message as $value) // Loop through input string array
{
$thisValueASCII = ord($value);
if($thisValueASCII >= 65 && $thisValueASCII <= 90) // if is uppercase
{
$thisValueASCIIOffset = 65;
} else // if is lowercase
{
$thisValueASCIIOffset = 97;
}
$letter_value_corrected = $thisValueASCII - $thisValueASCIIOffset;
$key_index_corrected = $keyIndex % $keyLength; // This is the same as fmod but I prefer this notation.
$key_ascii_value = ord($key[$key_index_corrected]);
if($key_ascii_value >= 65 && $key_ascii_value <= 90) // if is uppercase
{
$key_offset = 65;
} else // if is lowercase
{
$key_offset = 97;
}
$final_key = $key_ascii_value - $key_offset;
$letter_value_encrypted = ($letter_value_corrected + $final_key)%26;
$output = $output . chr($letter_value_encrypted + $thisValueASCIIOffset);
$keyIndex++;
}
echo $output;
Have fun and good luck for your implementation !

Increment individual IPs from IPv6 string (php)

What is a simple, elegant way to list the first x number of IPv6 IPs from a IPv6 string.
For example,
listIPs("2600:f333:10:c000::0", 4)
echos
2600:f333:10:c000::1
2600:f333:10:c000::2
2600:f333:10:c000::3
2600:f333:10:c000::4
Here's a sample of code that may have worked for IPv4, as it converted to int:
$input = "2600:f333:10:c000::/51";
$max = 4;
list($block, $cidr) = explode("/", $input);
$first = inet_pton( $block );
echo inet_ntop($first) . "\n";
for ($i = 1; $i < $max; $i++) {
//todo: die if it has exceeded block size based on $cidr
echo inet_ntop($first + $i) . "\n"; //doesn't work, packed binary?
}
Here's an example program written in C (since I don't know C++). It's fairly fast, but I'm not really happy with it. Maybe someone can help me improve it.
Edit: Obviously, I wrote this before it was turned into a PHP-only question. Turning this into PHP is left as an exercise to the reader (ew).
#include <arpa/inet.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <stdio.h>
#include <ctype.h>
/*
* Syntax: ./ipv6_list <ip>/<cidr-prefix>
*/
int main(int argc, char **argv) {
uint8_t start[16];
uint8_t address[16];
uint8_t mask[16] = { 0 };
uint8_t prefix = 128;
char *prefix_location;
int i;
/* This is the octet that, when changed, will result in <IP> & <mask> != <start IP> */
int mask_check_octet = 0;
if(argc != 2)
return 1;
/* Find prefix */
if((prefix_location = strstr(argv[1], "/")) != NULL) {
char *prefix_search = prefix_location + 1;
char *prefix_remaining;
long prefix_test;
if(!isdigit(*prefix_search))
return 2;
errno = 0;
prefix_test = strtol(prefix_search, &prefix_remaining, 10);
if(errno == ERANGE || prefix_test < 0 || prefix_test > 128 || strcmp(prefix_remaining, "") != 0)
return 2;
prefix = (uint8_t)prefix_test;
*prefix_location = '\0'; /* So we can just pass argv[1] into inet_pton(3) */
}
/* Convert prefix into mask */
for(i = 0; i < 16; i++) {
if(prefix == 0)
break;
mask_check_octet = i;
if(prefix < 8) {
mask[i] = ~((1 << (8 - prefix)) - 1);
break;
}
else
mask[i] = UINT8_MAX;
prefix -= 8;
}
/* Find address */
if(inet_pton(AF_INET6, argv[1], start) != 1)
return 3;
/* Start at the beginning of the network */
for(i = 0; i < 16; i++) {
start[i] &= mask[i];
address[i] = start[i];
}
/* Iterate */
while((address[mask_check_octet] & mask[mask_check_octet]) == start[mask_check_octet]) {
char address_str[INET6_ADDRSTRLEN];
inet_ntop(AF_INET6, address, address_str, sizeof(address_str));
printf("%s\n", address_str);
/* Add one to the address */
for(i = 15; i >= 0; i--) {
if(address[i] != UINT8_MAX)
break;
}
address[i]++;
for(i++; i < 16; i++)
address[i] = 0;
};
return 0;
}
You can use standard shell commands to limit its output (or just modify the while loop):
nfontes#brioche:~$ ./ipv6_list '2607:fc50:0:d00::0/106' | head -n 200
2607:fc50:0:d00::
2607:fc50:0:d00::1
2607:fc50:0:d00::2
2607:fc50:0:d00::3
2607:fc50:0:d00::4
2607:fc50:0:d00::5
2607:fc50:0:d00::6
2607:fc50:0:d00::7
2607:fc50:0:d00::8
2607:fc50:0:d00::9
2607:fc50:0:d00::a
2607:fc50:0:d00::b
2607:fc50:0:d00::c
2607:fc50:0:d00::d
2607:fc50:0:d00::e
[...]
2607:fc50:0:d00::c0
2607:fc50:0:d00::c1
2607:fc50:0:d00::c2
2607:fc50:0:d00::c3
2607:fc50:0:d00::c4
2607:fc50:0:d00::c5
2607:fc50:0:d00::c6
2607:fc50:0:d00::c7
Something similar (in PHP). It takes an IPv4/IPv6 address and increments it by given value:
// Takes an IPv4/IPv6 address in string format, and increments it by given value
function incrementIp($ip, $increment)
{
$addr = inet_pton ( $ip );
for ( $i = strlen ( $addr ) - 1; $increment > 0 && $i >= 0; --$i )
{
$val = ord($addr[$i]) + $increment;
$increment = $val / 256;
$addr[$i] = chr($val % 256);
}
return inet_ntop ( $addr );
}

PHP - Optimization - Levenshtein distance with prioritization

I am trying to implement the levenshtein algorithm with a little addon. I want to prioritize values that have consecutive matching letters. I've tried implementing my own form of it using the code below:
function levenshtein_rating($string1, $string2) {
$GLOBALS['lvn_memo'] = array();
return lev($string1, 0, strlen($string1), $string2, 0, strlen($string2));
}
function lev($s1, $s1x, $s1l, $s2, $s2x, $s2l, $cons = 0) {
$key = $s1x . "," . $s1l . "," . $s2x . "," . $s2l;
if (isset($GLOBALS['lvn_memo'][$key])) return $GLOBALS['lvn_memo'][$key];
if ($s1l == 0) return $s2l;
if ($s2l == 0) return $s1l;
$cost = 0;
if ($s1[$s1x] != $s2[$s2x]) $cost = 1;
else $cons -= 0.1;
$dist = min(
(lev($s1, $s1x + 1, $s1l - 1, $s2, $s2x, $s2l, $cons) + 1),
(lev($s1, $s1x, $s1l, $s2, $s2x + 1, $s2l - 1, $cons) + 1),
(lev($s1, $s1x + 1, $s1l - 1, $s2, $s2x + 1, $s2l - 1, $cons) + $cost)
);
$GLOBALS['lvn_memo'][$key] = $dist + $cons;
return $dist + $cons;
}
You should note the $cons -= 0.1; is the part where I am adding a value to prioritize consecutive values. This formula will be checking against a large database of strings. (As high as 20,000 - 50,000) I've done a benchmark test with PHP's built in levenshtein
Message Time Change Memory
PHP N/A 9300128
End PHP 1ms 9300864
End Mine 20ms 9310736
Array
(
[0] => 3
[1] => 3
[2] => 0
)
Array
(
[0] => 2.5
[1] => 1.9
[2] => -1.5
)
Benchmark Test Code:
$string1 = "kitten";
$string2 = "sitter";
$string3 = "sitting";
$log = new Logger("PHP");
$distances = array();
$distances[] = levenshtein($string1, $string3);
$distances[] = levenshtein($string2, $string3);
$distances[] = levenshtein($string3, $string3);
$log->log("End PHP");
$distances2 = array();
$distances2[] = levenshtein_rating($string1, $string3);
$distances2[] = levenshtein_rating($string2, $string3);
$distances2[] = levenshtein_rating($string3, $string3);
$log->log("End Mine");
echo $log->status();
echo "<pre>" . print_r($distances, true) . "</pre>";
echo "<pre>" . print_r($distances2, true) . "</pre>";
I recognize that PHP's built in function will probably always be faster than mine by nature. But I am wondering if there is a way to speed mine up?
So the question: Is there a way to speed this up? My alternative here is to run levenshtein and then search through the highest X results of that and prioritize them additionally.
Based on Leigh's comment, copying PHP's built in form of Levenhstein lowered the time down to 3ms. (EDIT: Posted the version with consecutive character deductions. This may need tweaked, by appears to work.)
function levenshtein_rating($s1, $s2, $cons = 0, $cost_ins = 1, $cost_rep = 1, $cost_del = 1) {
$s1l = strlen($s1);
$s2l = strlen($s2);
if ($s1l == 0) return $s2l;
if ($s2l == 0) return $s1l;
$p1 = array();
$p2 = array();
for ($i2 = 0; $i2 <= $s2l; ++$i2) {
$p1[$i2] = $i2 * $cost_ins;
}
$cons = 0;
$cons_count = 0;
$cln = 0;
$tbl = $s1;
$lst = false;
for ($i1 = 0; $i1 < $s1l; ++$i1) {
$p2[0] = $p1[0] + $cost_del;
$srch = true;
for($i2 = 0; $i2 < $s2l; ++ $i2) {
$c0 = $p1[$i2] + (($s1[$i1] == $s2[$i2]) ? 0 : $cost_rep);
if ($srch && $s2[$i2] == $tbl[$i1]) {
$tbl[$i1] = "\0";
$srch = false;
$cln += ($cln == 0) ? 1 : $cln * 1;
}
$c1 = $p1[$i2 + 1] + $cost_del;
if ($c1 < $c0) $c0 = $c1;
$c2 = $p2[$i2] + $cost_ins;
if ($c2 < $c0) $c0 = $c2;
$p2[$i2 + 1] = $c0;
}
if (!$srch && $lst) {
$cons_count += $cln;
$cln = 0;
}
$lst = $srch;
$tmp = $p1;
$p1 = $p2;
$p2 = $tmp;
}
$cons_count += $cln;
$cons = -1 * ($cons_count * 0.1);
return $p1[$s2l] + $cons;
}
I think the major slowdown in your function is the fact that it's recursive.
As I've said in my comments, PHP function calls are notoriously heavy work for the engine.
PHP itself implements levenshtein as a loop, keeping a running total of the cost incurred for inserts, replacements and deletes.
I'm sure if you converted your code to a loop as well you'd see some massive performance increases.
I don't know exactly what your code is doing, but I have ported the native C code to PHP to give you a starting point.
define('LEVENSHTEIN_MAX_LENGTH', 12);
function lev2($s1, $s2, $cost_ins = 1, $cost_rep = 1, $cost_del = 1)
{
$l1 = strlen($s1);
$l2 = strlen($s2);
if ($l1 == 0) {
return $l2 * $cost_ins;
}
if ($l2 == 0) {
return $l1 * $cost_del;
}
if (($l1 > LEVENSHTEIN_MAX_LENGTH) || ($l2 > LEVENSHTEIN_MAX_LENGTH)) {
return -1;
}
$p1 = array();
$p2 = array();
for ($i2 = 0; $i2 <= $l2; $i2++) {
$p1[$i2] = $i2 * $cost_ins;
}
for ($i1 = 0; $i1 < $l1; $i1++) {
$p2[0] = $p1[0] + $cost_del;
for ($i2 = 0; $i2 < $l2; $i2++) {
$c0 = $p1[$i2] + (($s1[$i1] == $s2[$i2]) ? 0 : $cost_rep);
$c1 = $p1[$i2 + 1] + $cost_del;
if ($c1 < $c0) {
$c0 = $c1;
}
$c2 = $p2[$i2] + $cost_ins;
if ($c2 < $c0) {
$c0 = $c2;
}
$p2[$i2 + 1] = $c0;
}
$tmp = $p1;
$p1 = $p2;
$p2 = $tmp;
}
return $p1[$l2];
}
I did a quick benchmark comparing yours, mine, and PHPs internal functions, 100,000 iterations each, time is in seconds.
float(12.954766988754)
float(2.4660499095917)
float(0.14857912063599)
Obviously it hasn't got your tweaks in it yet, but I'm sure they wont slow it down that much.
If you really need more of a speed boost, once you have worked out how to change this function, it should be easy enough to port your changes back into C, make a copy of PHPs function definitions, and implement your own native C version of your modified function.
There's lots of tutorials out there on how to make PHP extensions, so you shouldn't have that much difficulty if you decide to go down that route.
Edit:
Was looking at ways to improve it further, I noticed
$c0 = $p1[$i2] + (($s1[$i1] == $s2[$i2]) ? 0 : $cost_rep);
$c1 = $p1[$i2 + 1] + $cost_del;
if ($c1 < $c0) {
$c0 = $c1;
}
$c2 = $p2[$i2] + $cost_ins;
if ($c2 < $c0) {
$c0 = $c2;
}
Is the same as
$c0 = min(
$p1[$i2 + 1] + $cost_del,
$p1[$i2] + (($s1[$i1] == $s2[$i2]) ? 0 : $cost_rep),
$c2 = $p2[$i2] + $cost_ins
);
Which I think directly relates to the min block in your code. However, this slows down the code quite significantly. (I guess its the overhead of the extra function call)
Benchmarks with the min() block as the second timing.
float(2.484846830368)
float(3.6055288314819)
You were right about the second $cost_ins not belonging - copy/paste fail on my part.

Categories