分类 PHP 下的文章

PHP 加密:关于 ENPHP 加密之注释加密说明

最近 ENPHP 上线了两种注释加密,

这也是我个人在代码加密混淆的实际应用场景里最常用的两种方法:

1、隐藏代码

示例:

/*<hide>*/
echo 1;
/*</hide>*/

能在加密混淆前,去掉

   echo 1;

这样,中间有部分逻辑就会去除。

语法说明:

/*<hide>*/
需要隐藏的代码
/*</hide>*/
/*<hide>*/和/*</hide>*/字符串固定,<和>之间不能有任何空格,hide只能小写

应用场景?我举个例子:

  • 你需要加密一部分代码给第三方,但是中间有些核心方法他们用不到。
  • 你的商业代码,但是在打包时,你只想隐藏一部分功能给用户。

2、字符串+数字加密

示例:

    $a = /*<encode>*/"明文数据1"/*</encode>*/;
    echo /*<encode>*/2/*</encode>*/;
    print(/*<encode>*/"明文数据3"/*</encode>*/);

加强字符串混淆强度,即使反编译后仍无法找到原字符串,使 hacker 们反编译后依旧无法正常阅读。

语法:

/*<encode>*/'字符串'/*</encode>*/
/*<encode>*/"字符串"/*</encode>*/
/*<encode>*/123/*</encode>*/

仅支持字符串变量和数字,如果中间是其它格式将不会转换。同理,encode 前后<和>都不能有空格

应用场景:

  • 假如你做的是一个商业软件,要限制域名。对域名加密判断过程可以这样写(仅供参考):
$domain = /*<encode>*/'djunny.com'/*</encode>*/;
$message = /*<encode>*/'Plz Register'/*</encode>*/;
if(strpos($_SERVER['HTTP_HOST'], $domain) !== false){
   exit($message);
}

当然,还有一个更加优化版本:

$a = 'd';
$b = 'j';
$k = '*';
$domain = str_replace($k, '', $a.$k.$b.$k)./*<encode>*/'unny.com'/*</encode>*/;
$message = /*<encode>*/'Plz Register'/*</encode>*/;
if(strpos($_SERVER['HTTP_HOST'], $domain) !== false){
   exit($message);
}

随意发挥~

好了,先说到这,有什么问题可以留言给我。

如何在PHP7中安装ImageMagick扩展(centos版)

(YUM 安装 PHP7 的方法在这里:PHP7安装

yum 命令(先安装 php7、PHP7-devel、ImageMagick-devel):

yum install -y php70w php70w-devel ImageMagick-devel

mkdir download/
cd download/
git clone https://github.com/mkoppanen/imagick.git
cd imagick
phpize
./configure
make && sudo make install
echo extension=imagick.so >> /etc/php.d/imagick.ini

然后,看看扩展是否正常安装:

php -m | grep imagick

返回结果为imagick 即安装成功。

用PHP实现 HTTP断点续传、分块下载文件(Socket)

最近尝试使用 PHP 在做一些后台的定时任务,包括大文件的下载。

想看看网上是否有满足需求的代码,找了半天无果,于是撸撸袖子自己写了一枚,

废话不说,上代码:

<?php

/**
 * User: djunny
 * Date: 2016-04-29
 * Time: 17:18
 * Mail: 199962760@qq.com
 * 支持断点下载的类
 */
class downloader {

    /**
     * download file to local path
     *
     * @param       $url
     * @param       $save_file
     * @param int   $speed
     * @param array $headers
     * @param int   $timeout
     * @return bool
     * @throws Exception
     */
    static function get($url, $save_file, $speed = 10240, $headers = array(), $timeout = 10) {
        $url_info = self::parse_url($url);
        if (!$url_info['host']) {
            throw new Exception('Url is Invalid');
        }

        // default header
        $def_headers = array(
            'Accept'          => '*/*',
            'User-Agent'      => 'Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0)',
            'Accept-Encoding' => 'gzip, deflate',
            'Host'            => $url_info['host'],
            'Connection'      => 'Close',
            'Accept-Language' => 'zh-cn',
        );

        // merge heade
        $headers = array_merge($def_headers, $headers);
        // get content length
        $content_length = self::get_content_size($url_info['host'], $url_info['port'], $url_info['request'], $headers, $timeout);

        // content length not exist
        if (!$content_length) {
            throw new Exception('Content-Length is Not Exists');
        }
        // get exists length
        $exists_length = is_file($save_file) ? filesize($save_file) : 0;
        // get tmp data file
        $data_file = $save_file . '.data';
        // get tmp data
        $exists_data = is_file($data_file) ? json_decode(file_get_contents($data_file), 1) : array();
        // check file is valid
        if ($exists_length == $content_length) {
            $exists_data && @unlink($data_file);
            return true;
        }
        // check file is expire
        if ($exists_data['length'] != $content_length || $exists_length > $content_length) {
            $exists_data = array(
                'length' => $content_length,
            );
        }
        // write exists data
        file_put_contents($data_file, json_encode($exists_data));

        try {
            $download_status = self::download_content($url_info['host'], $url_info['port'], $url_info['request'], $save_file, $content_length, $exists_length, $speed, $headers, $timeout);
            if ($download_status) {
                @unlink($data_file);
            }
        } catch (Exception $e) {
            throw new Exception($e->getMessage());
        }
        return true;
    }

    /**
     * parse url
     *
     * @param $url
     * @return bool|mixed
     */
    static function parse_url($url) {
        $url_info = parse_url($url);
        if (!$url_info['host']) {
            return false;
        }
        $url_info['port']    = $url_info['port'] ? $url_info['host'] : 80;
        $url_info['request'] = $url_info['path'] . ($url_info['query'] ? '?' . $url_info['query'] : '');
        return $url_info;
    }

    /**
     * download content by chunk
     *
     * @param $host
     * @param $port
     * @param $url_path
     * @param $headers
     * @param $timeout
     */
    static function download_content($host, $port, $url_path, $save_file, $content_length, $range_start, $speed, &$headers, $timeout) {
        $request = self::build_header('GET', $url_path, $headers, $range_start);
        $fsocket = @fsockopen($host, $port, $errno, $errstr, $timeout);
        stream_set_blocking($fsocket, TRUE);
        stream_set_timeout($fsocket, $timeout);
        fwrite($fsocket, $request);
        $status = stream_get_meta_data($fsocket);
        if ($status['timed_out']) {
            throw new Exception('Socket Connect Timeout');
        }
        $is_header_end = 0;
        $total_size    = $range_start;
        $file_fp       = fopen($save_file, 'a+');
        while (!feof($fsocket)) {
            if (!$is_header_end) {
                $line = @fgets($fsocket);
                if (in_array($line, array("\n", "\r\n"))) {
                    $is_header_end = 1;
                }
                continue;
            }
            $resp        = fread($fsocket, $speed);
            $read_length = strlen($resp);
            if ($resp === false || $content_length < $total_size + $read_length) {
                fclose($fsocket);
                fclose($file_fp);
                throw new Exception('Socket I/O Error Or File Was Changed');
            }
            $total_size += $read_length;
            fputs($file_fp, $resp);
            // check file end
            if ($content_length == $total_size) {
                break;
            }
            sleep(1);
            // for test
            //break;
        }
        fclose($fsocket);
        fclose($file_fp);
        return true;

    }

    /**
     * get content length
     *
     * @param $host
     * @param $port
     * @param $url_path
     * @param $headers
     * @param $timeout
     * @return int
     */
    static function get_content_size($host, $port, $url_path, &$headers, $timeout) {
        $request = self::build_header('HEAD', $url_path, $headers);
        $fsocket = @fsockopen($host, $port, $errno, $errstr, $timeout);
        stream_set_blocking($fsocket, TRUE);
        stream_set_timeout($fsocket, $timeout);
        fwrite($fsocket, $request);
        $status = stream_get_meta_data($fsocket);
        $length = 0;
        if ($status['timed_out']) {
            return 0;
        }
        while (!feof($fsocket)) {
            $line = @fgets($fsocket);
            if (in_array($line, array("\n", "\r\n"))) {
                break;
            }
            $line = strtolower($line);
            // get location
            if (substr($line, 0, 9) == 'location:') {
                $location = trim(substr($line, 9));
                $url_info = self::parse_url($location);
                if (!$url_info['host']) {
                    return 0;
                }
                fclose($fsocket);
                return self::get_content_size($url_info['host'], $url_info['port'], $url_info['request'], $headers, $timeout);
            }
            // get content length
            if (strpos($line, 'content-length:') !== false) {
                list(, $length) = explode('content-length:', $line);
                $length = (int)trim($length);
            }
        }
        fclose($fsocket);
        return $length;

    }

    /**
     * build header for socket
     *
     * @param     $action
     * @param     $url_path
     * @param     $headers
     * @param int $range_start
     * @return string
     */
    static function build_header($action, $url_path, &$headers, $range_start = -1) {
        $out = $action . " {$url_path} HTTP/1.0\r\n";
        foreach ($headers as $hkey => $hval) {
            $out .= $hkey . ': ' . $hval . "\r\n";
        }
        if ($range_start > -1) {
            $out .= "Accept-Ranges: bytes\r\n";
            $out .= "Range: bytes={$range_start}-\r\n";
        }
        $out .= "\r\n";

        return $out;
    }
}

?>

用法很简单:

try {
if (downloader::get('http://dzs.aqtxt.com/files/11/23636/201604230358308081.rar', 'test.rar')) {
//todo
echo 'Download Succ';
}
} catch (Exception $e) {
echo 'Download Failed';
}

关于 php 代码混淆加密

2015 年初,利用业余时间开发了一套站群系统,手上掌管了近 300 多个域名和站点。

随着系统的商业化,站群系统需要对外出售,不得不对站群系统的代码进行加密。

研究了些市面上的 PHP 加密组件,发现除了eval、base64_encode等方式加密外,几乎没有任何门槛,分分钟破解。

心有不甘,笔者怀着一颗尝试的心,开始研究PHP混淆加密,并落实实现一套完整的混淆加密的方案:

  1. 混淆强度要高(毕竟PHP有着灵活的语法,实现起来)

  2. 加密方式性能损耗要控制在1%以内。(这点要求就不能使用eval、base64这种方式)

  3. 不依赖扩展

加密系统应用的场景为:

  1. 核心代码加密混淆。

  2. 模板加密。

  3. 图片、二进制文件加密。

通过研究市面的一些加密引擎和不断尝试后,最终系统终于面市,取名 EnPHP:

http://enphp.djunny.com/

混淆是EnPHP的最大特色,它能混淆系统里的变量、方法和类,使用unicode的编码方式,使得PHP源代码无法阅读。

EnPHP不会对代码进行修改逻辑、和注入相关代码,以至于过度加密,因为再加密的代码也是需要机器解码运行的。

经过大量 TestCase 和 5w+ 行系统测试和使用, 现 EnPHP 引擎已经内嵌于 mzphp2 框架中,为开发者们免费使用。