【问题标题】:php - help improve the efficiency of this youtube style url generatorphp - 帮助提高这个 youtube 风格的 url 生成器的效率
【发布时间】:2010-12-23 15:11:50
【问题描述】:

经过一番搜索,我发现了这个 youtube 风格的 url 生成器,它带有加密功能,可以隐藏原始 id……但是我希望能提高效率,因为它会被大量使用。到目前为止,我已经改进了 20%...谁能帮我改进更多。

这是原文:

function alphaID($in, $to_num = false, $pad_up = false, $passKey = null)
{
    $index = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    if ($passKey !== null) {
        // Although this function's purpose is to just make the
        // ID short - and not so much secure,
        // with this patch by Simon Franz (http://blog.snaky.org/)
        // you can optionally supply a password to make it harder
        // to calculate the corresponding numeric ID

        for ($n = 0; $n<strlen($index); $n++) {
            $i[] = substr( $index,$n ,1);
        }

        $passhash = hash('sha256',$passKey);
        $passhash = (strlen($passhash) < strlen($index))
            ? hash('sha512',$passKey)
            : $passhash;

        for ($n=0; $n < strlen($index); $n++) {
            $p[] = substr($passhash, $n ,1);
        }

        array_multisort($p, SORT_DESC, $i);
        $index = implode($i);
    }

    $base = strlen($index);

    if ($to_num) {
        // Digital number <<-- alphabet letter code
        $in = strrev($in);
        $out = 0;
        $len = strlen($in) - 1;
        for ($t = 0; $t <= $len; $t++) {
            $bcpow = bcpow($base, $len - $t);
            $out = $out + strpos($index, substr($in, $t, 1)) * $bcpow;
        }

        if (is_numeric($pad_up)) {
            $pad_up--;
            if ($pad_up > 0) {
                $out -= pow($base, $pad_up);
            }
        }
    } else {
        // Digital number -->> alphabet letter code
        if (is_numeric($pad_up)) {
            $pad_up--;
            if ($pad_up > 0) {
                $in += pow($base, $pad_up);
            }
        }

        $out = "";
        for ($t = floor(log10($in) / log10($base)); $t >= 0; $t--) {
            $a = floor($in / bcpow($base, $t));
            $out = $out . substr($index, $a, 1);
            $in = $in - ($a * bcpow($base, $t));
        }
        $out = strrev($out); // reverse
    }

    return $out;
}

这是我目前修改的代码:

function alphaID($in, $to_num = false, $pad_up = false, $passKey = null)
{
    $index = 'abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ';
    $i = array('a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z');
    if ($passKey !== null) {
        // Although this function's purpose is to just make the
        // ID short - and not so much secure,
        // with this patch by Simon Franz (http://blog.snaky.org/)
        // you can optionally supply a password to make it harder
        // to calculate the corresponding numeric ID
       $len = strlen($index); 


        $passhash = hash('sha256',$passKey);
        $passhash = (strlen($passhash) < $len)
            ? hash('sha512',$passKey)
            : $passhash;

        for ($n=0; $n < $len; $n++) {
            $p[] = substr($passhash, $n ,1);
        }

        array_multisort($p, SORT_DESC, $i);
        $index = implode($i);
    }

    $base = strlen($index);

    if ($to_num) {
        // Digital number <<-- alphabet letter code
        $in = strrev($in);
        $out = 0;
        $len = strlen($in) - 1;
        for ($t = 0; $t <= $len; $t++) {
            $bcpow = bcpow($base, $len - $t);
            $out = $out + strpos($index, substr($in, $t, 1)) * $bcpow;
        }

        if (is_numeric($pad_up)) {
            $pad_up--;
            if ($pad_up > 0) {
                $out -= pow($base, $pad_up);
            }
        }
    } else {
        // Digital number -->> alphabet letter code
        if (is_numeric($pad_up)) {
            $pad_up--;
            if ($pad_up > 0) {
                $in += pow($base, $pad_up);
            }
        }

        $out = "";
        for ($t = floor(log10($in) / log10($base)); $t >= 0; $t--) {
            $a = floor($in / bcpow($base, $t));
            $out = $out . substr($index, $a, 1);
            $in = $in - ($a * bcpow($base, $t));
        }
        $out = strrev($out); // reverse
    }

    return $out;
}

你看不出有什么大的区别,只是我从 for 循环中删除了 strlen 并将其存储在一个变量中,并为索引预先计算了数组(有点笨拙......但是数组生成是组成大部分计算)。

应得的信用:这是原始作者信息: * @作者凯文·范·佐内维尔德 * @作者西蒙弗兰兹 * @copyright 2008 Kevin van Zonneveld (kevin dot vanzonneveld dot net) * @license www dot opensource dot org/licenses/bsd-license dot php 新 BSD 许可证 * @version SVN:发布:$Id:alphaID.inc.php 344 2009-06-10 17:43:59Z kevin $ * @link kevin dot vanzonneveld dot net

我不能发布网址,因为我的声誉很低:S

【问题讨论】:

  • 您是否尝试过分析此代码(使用例如 XDebug)来查找瓶颈?我还没有发现任何直接影响性能的因素。

标签: php performance


【解决方案1】:

我认为您应该只生成一个索引并在整个站点范围内使用它。让我解释一下原因...

$base = strlen($index); 上面的散列和所有内容只是为了生成索引...您必须使用相同的 $passkey 来解码 url。由于您无法知道使用了哪个密码,因此您必须将其设置为站点范围。这意味着生成 url 的每个调用都将使用相同的密码,从而生成相同的索引。

所以...我将剥离索引生成代码并生成唯一索引并将其存储在$index 变量中。

【讨论】:

    【解决方案2】:

    我做了一些轻微的优化,以消除一些额外的 CPU 周期。主要是诸如不必要的分配、额外的比较等。此外,字符串可以被视为数组,所以我也这样做了:

    function alphaID($in, $to_num = false, $pad_up = false, $passKey = null)
    {
        static $passcache;
        if(empty($passcache))
            $passcache = array();
    
        $index = 'abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ';
        $i = array('a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z');
        if (!empty($passKey)) {
            // Although this function's purpose is to just make the
            // ID short - and not so much secure,
            // with this patch by Simon Franz (http://blog.snaky.org/)
            // you can optionally supply a password to make it harder
            // to calculate the corresponding numeric ID
    
            if(isset($passcache[$passKey]))
                $index = $passcache[$passKey];
            else {
                if(strlen($passhash = hash('sha256',$passKey)) < strlen($index))
                    $passhash = hash('sha512',$passKey);
    
                $p = str_split($passhash);
    
                array_multisort($p, SORT_DESC, $i);
                $index = implode($i);
                $passcache = $index;
            }
        }
    
        $base = strlen($index);
    
        if ($to_num) {
            // Digital number <<-- alphabet letter code
            $in = strrev($in);
            $out = 0;
            $len = strlen($in) - 1;
            for ($t = 0; $t <= $len; $t++) {
                $bcpow = bcpow($base, $len - $t);
                $out += strpos($index, $in[$t]) * $bcpow;
            }
    
            if (is_numeric($pad_up)) {
                $pad_up--;
                if ($pad_up > 0) {
                    $out -= pow($base, $pad_up);
                }
            }
        } else {
            // Digital number -->> alphabet letter code
            if (is_numeric($pad_up)) {
                $pad_up--;
                if ($pad_up > 0) {
                    $in += pow($base, $pad_up);
                }
            }
    
            $out = "";
            for ($t = floor(log10($in) / log10($base)); $t >= 0; $t--) {
                $bcp = bcpow($base, $t);
                $a = floor($in / $bcp);
                $out .= $index[$a];
                $in -= $a *  $bcp;
            }
            $out = strrev($out); // reverse
        }
    
        return $out;
    }
    

    编辑:我已更新为包含缓存。现在就试试吧!

    【讨论】:

    • 哇……你做得很棒……1000 次执行过去需要 600 毫秒……现在只需 250 毫秒。您的代码中的一个小错误是,如果它们的长度不同,array_multisort 会导致错误......所以我添加了这个: $p = array_shift(array_chunk ($p, $len));也就是说... 250 中的 100 毫秒是 array_multisort... 有什么更有效的替代解决方案的想法吗?
    • 我刚刚进行的更新在您第一次运行时会有 100 毫秒的延迟,但随后的每次运行都会快得多。让我知道它是否有效!
    【解决方案3】:

    看起来您在摆脱冗余调用方面做得很好。

    看起来有几个对 bcpow($base, $t) 的调用可以减少到一个......

    $out = "";
    for ($t = floor(log10($in) / log10($base)); $t >= 0; $t--) {
        $newbase = bcpow($base, $t);
        $a = floor($in / $newbase);
        $out = $out . substr($index, $a, 1);
        $in = $in - ($a * $newbase);
    }
    $out = strrev($out); // reverse
    

    您可能不会注意到差异。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-06-23
      • 2023-03-03
      • 1970-01-01
      • 2014-06-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多