[精讚] [會員登入]
5

PHP 數字加解密函式

自寫的數字加解密,勉強用

此文完整連結 http://n.sfs.tw/12797

複製連結 PHP 數字加解密函式@新精讚
(文章歡迎轉載,務必尊重版權註明連結來源)
2018-10-12 00:52:50 最後編修
2018-10-12 01:03:14 By 瘦河馬
 

在 URL 中常會有帶出參數的情況,其中可能有數字。例如 http://n.sfs.tw/?n=123456

但是手賤的使用者(就是我) 會企圖去修改這個數字,+1看看會出現什麼

http://n.sfs.tw/?n=123457

結果就和總統府網站中馬英九的治國日記被看到明天的內容一樣出狀況,為了解決使用者改數字的問題,

設計了一個正整數加解密函數。

例如上例的123456,改為加密的字串:

http://n.sfs.tw/?n=99ht

使用者無法將 99ht +1,就算是變成 99hu 也無法得到文章的正確數字。

上面是想法,想直接看解法的話捲到最下面。

一、現況分析

現有的雙向 hash 函數,如 base64 ,會產生過長的字串,整體看來不美觀。因為要加密的只有數字,應該不必這麼麻煩。

參考已有的整數 HASH,這裡參考了 Thomas Wang 的網站(連結佚失),其中有他的整數HASH算法

/**
 * Thomas Wang的算法,整数hash
*/
function intHash($k)
{
  $k = ~$k + ($k << 15); // $k = ($k << 15) - $k - 1;
  $k = $k ^ SHR($k,12);
  $k = $k + ($k << 2);
  $k = $k ^ SHR($k,4);
  $k = $k * 2057; // $k = ($k + ($k << 3)) + ($k << 11);
  $k = $k ^ SHR($k,16);
  return $k;
}

function SHR($x, $n)    // x >>> n
{
    $mask = 0x40000000;
    if ($x < 0)
    {
        $x &= 0x7FFFFFFF;
        $mask = $mask >> ($n-1);
        return ($x >> $n) | $mask;
    }
    return (int)$x >> (int)$n;
}

因為php並沒有 >>> 這個運算子,所以上面的 SHR 函式我把他寫成函數。

OK,看起來一切都不錯?但是?怎麼解hash值…?原站沒有提供 decode 的函式

看來是行不通的,如果沒辦法把 HASH過的值寫回就沒意義了。

 

二、自寫函數初稿

所以我花了二個多小時,寫了二個整數的加解密函數:

function iencode($v){
  $code="OlPkQjRiShTgUfAz5By6Cx7Dw8Ev9Fu0Gt1Hs2Ir3Jq4KpLoMnNmVeWdXcYbZa";    //想要使用的字串符,字元不得重覆。
  $shift=6;
  $len = strlen($code);
  $v = ($v <<  $shift);
  $out="";
  do{
    $r = $v%$len;
    $out .= $code[$r];
    $v = ($v - $r)/$len;
  }while($v>0);
  return $out;
}

function idecode($s){
  $code="OlPkQjRiShTgUfAz5By6Cx7Dw8Ev9Fu0Gt1Hs2Ir3Jq4KpLoMnNmVeWdXcYbZa";
  $shift=6;
  $len = strlen($code);
  $in=0;
  for($ii=0;$ii<strlen($s);$ii++){
    $r=strpos($code, $s[$ii]);
    $in += $r* pow($len,$ii);
  }
  $in = ($in >>$shift);
  return $in;
}

看來 WORK fine,可惜,輸入的 $v 值太大會有溢位的問題,最大只能接受 約32,000,000的正整數

叫用例:
print iencode(123456);   //99ht
print idecode("99ht"); //123456

所以上面的函式不OK。

 

三、自寫函數改良

再花四個小時改善原程式,加強了以下功能:

1. 可接受任意值整數,不必擔心溢位的問題;

2. 有檢查加密字串是否合法的功能

 

// Number Encode/Decode class By Axer 991208
class LongDEnCrypt{
  var $code="OlPkQjRiShTgUfAz5By6Cx7Dw8Ev9Fu0Gt1Hs2Ir3Jq4KpLoMnNmVeWdXcYbZa"; // A character string without dupl. char.
  var $shift=6;  //shift value : no shift 0-10 largely shift

 /**
  * function LongEncode(): Encrypted a integer to a string.
  * @scope public
  * @param string $v input number
  * @return encrypted integer string
  * ex. LongEncode("5611236889745123")   //IBmyw1tytILDi
  */
  public function LongEncode($v){
    $code= $this->code;
    $shift=$this->shift;
    $len = strlen($code); //62
    $vs = (string)$v;
    $segment = floor( log10( PHP_INT_MAX >>$shift));  //7
    $segnum = ceil(strlen($vs)/ $segment);
    $out="";
    for($ii=0; $ii<$segnum;$ii++){
      $seg = substr($vs,$ii*$segment, $segment);
      $v = (int)$seg <<$shift;
      if($v===0){
        $zeronum =strlen($seg);
        $out .= ".". $code[$zeronum];
      }
      else
        do{
          $r = $v%$len;
          $out .= $code[$r];
          $v = ($v - $r)/$len;
        }while($v>0);
    }
    // Add check char.
    $c=0;
    for($ii=0;$ii< strlen($out);$ii++)if($out[$ii]!=='.') $c+=strpos($code, $out[$ii]);
    $out .= $code[$c%$len];
    return $out;
  }

 /**
  * function LongDecode(): Decrypted a string to a number string.
  * @scope public
  * @param string $s encrypted string
  * @return -1: string too short, -2: not a valid encrypted string and success: a number string
  * ex. LongDecode("Bmyw1tytILDi"); //5611236889745123
  * ex. $obj= new LongDEnCrypt();
  *     if( $v=$obj->LongDecode("SOMESTRING") <=0) print "Invalid encrypted string"; //Error control
  *     else // Do something
  */
 public function LongDecode($s){
    $code=  $this->code;
    $shift= $this->shift;  //6
    //check decoded string
    $len = strlen($code);
    $slen = strlen($s)-1;
    if($slen<=1)return -1;
    $c=0;
    for($ii=0;$ii<$slen;$ii++)if($s[$ii]!=='.')$c+=strpos($code, $s[$ii]);
    if($code[$c%$len] !== $s[$slen])return -2;   //Validate Err
    $segment = ceil( log( PHP_INT_MAX >>$shift)/log($len) ); //5
    $out="";
    $ii=0;
    $index=0;
    $v=0;
    do{
      if($s[$index] !=="."){
        $r=strpos($code, $s[$index]);
        $v += $r* pow($len,$ii);
        if( $ii == $segment-1 || $index==$slen-1 ){
          $ii=0;
          $v >>= $shift;
          $out .= $v;
          $v=0;
        }
      }else{ //ZERO
        $pos= strpos($code, $s[$index+1]);
        $out .= str_repeat("0", $pos);
        $ii=0;
        $index++;
        $v=0;
      }
      $ii++;
      $index++;
    }while($index<$slen);
    return $out;
} //End Class

 

用來尚可,沒發現啥BUG


原文 2010-12-08 14:07:58

你可能感興趣的文章

[PHP] 讀取作業系統程式執行結果 PHP讀取作業系統程式執行結果

[PHP]解決ksort新增的SORT_NATURAL|SORT_FLAG_CASE方法 php>=5.4中ksort函數多了SORT_NATURAL 和 SORT_FLAG_CASE 旗標,對舊版的PHP中要怎麼辦?

[PHP] 取得檔名和路徑:basename, dirname 由絕對路徑取的路徑及檔名的方法

[PHP] IPv6檢查IP是否在某個網段內 mtachcidr6 要檢查IPv6是否在某個IPv6的網段內?

[PHP] 位元運算 (Bitwise operation)及和PERL比較 PHP 的位元運算,及和PERL比較整理

[PHP7] 讀取mysql資料庫的傳統方法 使用傳統預設的方法來連結mysql資料庫

[CodeIgniter 3] 資料庫的使用方法整理1/2 --Select的使用 [CodeIgniter 3] 資料庫的使用方法整理:Select的使用

[PHP] 陣列排序 sort, ksort, asort, usort... 簡單的記錄PHP的陣列排序,因為常常會用到。

[phpmyadmin] 缺少 mcrypt 外掛,請檢查 PHP 設定 缺少 mcrypt 外掛,請檢查 PHP 設定,安裝php-mcrypt。

[PHP] 類別中要怎麼使用callback function 召回函數(回呼函數)? 在類別中使用標準函數,若其中的callback 函數也是在類別中,該怎麼使用?

我有話要說


限制:留言最高字數1000字,超過部分會被截掉。請注意:留言不可帶有網址,會被濾掉。 限制:未登入訪客,每則留言間隔需超過10分鐘,每日最多5則留言。

訪客留言

[無留言]

隨機好文

[jQuery] 利用load()來達成ajax的寫法 jQuery中利用load()來達成ajax的寫法,也有人稱他是假的ajax,作法就是..

UTF-8 BOM (Byte Order Mark) 的問題 在 Michael Kaplan 那看到 Every character has a story #4: U+feff

如何在linux下執行java 原生的java應用程式可以使用簡單的方法在console下面寫出來,適合作簡單的應用

安裝SPHINX支援中文 新版本的 sphinx 和舊版不同,網路上很多範例和教學是不能用的。此文是安裝和設定方法分享

[Win7] 燒錄 iso 檔 在Windows7 中內建燒錄程式,可以直接把檔案拉到光碟機裡,再執行燒錄。