PHP翻译BLOB变成文件流

base64_encode(pack('H*', $data['image']));

上面先用pack把数据翻译成文件流,然后再把文件流base64,好在页面使用img元素输出

<img src="data:image/gif;base64,<?php echo $data['image'] ?>" />

这样就可以显示出图片了,不过图片不会被游览器缓存.

SuperSlide 致力于解决网站大部分特效展示问题,使网站代码规范整洁,方便维护更新.

SuperSlide+Swiper 一个PC一个移动端. 可以很方便的制作网站展示页面,使用也和简单.记录一下.方便使用

直接贴代码

self.edgesForExtendedLayout = UIRectEdgeNone;
self.extendedLayoutIncludesOpaqueBars = NO;
self.modalPresentationCapturesStatusBarAppearance = NO

直接上代码

// 获取销售属性
function get_sku_props($str) {
    $attr = array();
    $tmp_attr = explode('::', $str);
    $tmp_attr_str = $tmp_attr[0];

    $length = count($tmp_attr);
    for ($i = 1; $i < $length; $i++) {
        $strrchrlen = strrchr($tmp_attr[$i], ';');
        if (strlen($strrchrlen) > 1) {
            $nlen = strlen($strrchrlen) - 1;
            $tmp_attr_str = substr($tmp_attr[$i], -$nlen);
            $attr[] = array(substr($tmp_attr[$i], 0, strlen($tmp_attr[$i]) - $nlen), $tmp_attr_str);
        } else {
            $attr[] = array($tmp_attr[$i], $tmp_attr_str);
        }
    }

    return $attr;
}

代码如下

$link = mysql_connect('127.0.0.1', 'root', '');
mysql_select_db('wsdd');
mysql_query('SET NAMES utf8');
mysql_query('set @@sql_mode=\'no_engine_substitution\'');

$sql = 'SHOW TABLES';
$res = mysql_query($sql);

while ($row = mysql_fetch_assoc($res)) {
    $sql = 'show create table '.$row['Tables_in_wsdd'];
    $result = mysql_query($sql);
    while ($row1 = mysql_fetch_assoc($result)) {
        $sql_table = $row1['Create Table'];
        if (preg_match('/ENGINE=InnoDB.+CHARSET=utf8mb4/i', $sql_table) == false) {
            $sql = 'ALTER TABLE  `'.$row1['Table'].'` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci';
            mysql_query($sql);
        }
    }
}

$sql = 'SHOW TABLES';
$res = mysql_query($sql);

while ($row = mysql_fetch_assoc($res)) {
    $sql = 'show create table '.$row['Tables_in_wsdd'];
    $result = mysql_query($sql);
    while ($row1 = mysql_fetch_assoc($result)) {
        $sql_table = $row1['Create Table'];
        preg_match_all('/`.+varchar.+SET.+?,/i', $sql_table, $matches);
        foreach ($matches[0] as $item) {
            if (strpos('utf8mb4', $item) === false) {
                preg_match('/`(.+)?`/i', $item, $field);
                preg_match('/(VARCHAR\(.+?\))/i', $item, $varchar);
                preg_match('/COMMENT.+?\'(.+?)\'/i', $item, $comment);
                $sql = 'ALTER TABLE  `'.$row1['Table'].'` CHANGE  '.$field[0].'  '.$field[0].' '.$varchar[0].' CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT  \''.$comment[1].'\'';
                mysql_query($sql);
            }
        }
    }
}

mysql_close($link);

echo "SUCCESS";

直接上命令

1 set @@sql_mode='no_engine_substitution'
2 set global max_allowed_packet=524288000;
3 source file.sql

不多累述,直接上代码

<?php
/**
 * 代码进行上线操作
 * 
 * @version 1.0
 */
// 应用名称
define('APP_NAME', 'test-test');

// 指定代码处理空间
define('WORKSPACE', dirname(__FILE__) . DIRECTORY_SEPARATOR . 'tttt');

// 源代码的位置
define('SOURCE_WORKSPACE', dirname(__DIR__) . DIRECTORY_SEPARATOR . 'tttt');

require(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'func.php');

// 清空工作区间
sure_remove_dir(WORKSPACE);

// 整理代码
exec_code(SOURCE_WORKSPACE);

// 代码上线到服务器
push_code_online();

// 结束
echo date('Y-m-d H:i:s') . " SUCCESS\n";

// 推送代码到线上服务器
function push_code_online() {
    //需要进行代码部署的服务器列表
    $online_servers = array(
        array(
            'host' => '192.168.56.102',
            'user' => 'root',
            'pass' => '123123'
        )
    );

    // 开始进行软件打包
    $package_str = APP_NAME . '-' . date('Ymd-His').'.tar.gz';
    $push_package_file = PACKAGE_DIR . DIRECTORY_SEPARATOR . $package_str;
    shell_exec('cd '.WORKSPACE . DIRECTORY_SEPARATOR.'; tar cvf ' . $push_package_file . ' ' . './*');
    // 代码部署到应用服务器
    foreach ($online_servers as $server) {
        $command = <<<EOF
#!/usr/bin/expect -f 

spawn scp {$push_package_file} {$server['user']}@{$server['host']}:/root

expect "*password:" 

send "{$server['pass']}\\r"

expect eof
EOF;
        $scp_file = dirname(__FILE__) . '/scp';
        file_put_contents($scp_file, $command);
        chmod($scp_file, 0755);
        shell_exec($scp_file);
    }
    echo WORKSPACE . ' ' . $package_str . " 代码上线完毕\n";
}

// 整理数据代码
function exec_code($source_workspace) {
    foreach (glob($source_workspace.'/*') as $item) {
        $curr_item = str_replace(SOURCE_WORKSPACE, '', $item);
        if (is_file($item) && in_array(end(explode('.', $item)), array('sh', 'php'))) {

            // 去除配置文件
            if (substr($item, -10) == 'config.php') {
                continue;
            }

            copy($item, WORKSPACE . $curr_item);
        } elseif (is_dir($item)) {
            if (!file_exists(WORKSPACE . $curr_item)) {
                mkdir(WORKSPACE . $curr_item, 0777);
            }
            exec_code($item);
        }
    }
}

直接上代码

$arr = array('name1'=>"中文",'name2'=>'abc12','itmes'=>array(array('name'=>'小小', 'age' => 12)));
$jsonstr = decodeUnicode(json_encode($arr));;

print_r($jsonstr);

function decodeUnicode($str)
{
    return preg_replace_callback('/\\\\u([0-9a-f]{4})/i',
        create_function('$matches', 'return mb_convert_encoding(pack("H*", $matches[1]), "UTF-8", "UCS-2BE");'),
        $str
    );
}

nginx.conf

server {
    listen       80;
    server_name  test.think.cn;

    location / {
        if (!-e $request_filename){
            rewrite ^(.*)$ /index.php?s=$1 last;
            break;
        }
        root   /home/www/test.think.cn/public;
        index  index.php index.html index.htm;
    }

    location ~ \.php$ {
        root           html;
        fastcgi_split_path_info  ^(.+\.php)(.*)$;
        fastcgi_pass   127.0.0.1:9000;
        fastcgi_index  index.php;
        fastcgi_param  SCRIPT_FILENAME  /home/www/test.think.cn/public$fastcgi_script_name;
        include        fastcgi_params;
    }
}

PATHINFO模式

    server { listen 80; server_name test.think.cn;

    location / {
        root   /home/www/test.think.cn/public;
        index  index.php index.html index.htm;
    }

    location ~ \.php {
        root           html;
        fastcgi_pass   127.0.0.1:9000;
        fastcgi_index  index.php;
        set $path_info "";
        set $real_script_name $fastcgi_script_name;
        if ($fastcgi_script_name ~ "^(.+?\.php)(/.+)$") {
            set $real_script_name $1;
            set $path_info $2;
        }
        fastcgi_param  SCRIPT_FILENAME  /home/www/test.think.cn/public$fastcgi_script_name;
        fastcgi_param SCRIPT_NAME $real_script_name;
        fastcgi_param PATH_INFO $path_info;
        include        fastcgi_params;
    }
}

dumpsql.sh的代码如下

#!/bin/bash
#this script used montor mysql network traffic.echo sql
tcpdump -i lo -s 0 -l -w - dst port 3306 | strings | perl -e '
while(<>) { chomp; next if /^[^ ]+[ ]*$/;
    if(/^(SELECT|UPDATE|DELETE|INSERT|SET|COMMIT|ROLLBACK|CREATE|DROP|ALTER|CALL)/i)
    {
        if (defined $q) { print "$q\n"; }
        $q=$_;
    } else {
        $_ =~ s/^[ \t]+//; $q.=" $_";
    }
}'

配置数据库连接池


连接池配置

配置缓存


缓存配置(ehcache)

配置日志路径


修改文件 cas-server-webapp/src/main/resources/log4j2.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!-- Specify the refresh internal in seconds. -->
<Configuration monitorInterval="60">
    <Properties>
        <Property name="CAS_LOG_DIR">/tmp</Property>
    </Properties>
    <Appenders>
        <Console name="console" target="SYSTEM_OUT">
            <PatternLayout pattern="%d %p [%c] - &lt;%m&gt;%n"/>
        </Console>
        <RollingFile name="file" fileName="${CAS_LOG_DIR}/cas.log" append="true"
                     filePattern="cas-%d{yyyy-MM-dd-HH}-%i.log">
            <PatternLayout pattern="%d %p [%c] - %m%n"/>
            <Policies>
                <OnStartupTriggeringPolicy />
                <SizeBasedTriggeringPolicy size="10 MB"/>
                <TimeBasedTriggeringPolicy />
            </Policies>
        </RollingFile>
        <RollingFile name="auditlogfile" fileName="${CAS_LOG_DIR}/cas_audit.log" append="true"
                     filePattern="cas_audit-%d{yyyy-MM-dd-HH}-%i.log">
            <PatternLayout pattern="%d %p [%c] - %m%n"/>
            <Policies>
                <OnStartupTriggeringPolicy />
                <SizeBasedTriggeringPolicy size="10 MB"/>
                <TimeBasedTriggeringPolicy />
            </Policies>
        </RollingFile>
        <RollingFile name="perfFileAppender" fileName="${CAS_LOG_DIR}/perfStats.log" append="true"
                     filePattern="perfStats-%d{yyyy-MM-dd-HH}-%i.log">
            <PatternLayout pattern="%m%n"/>
            <Policies>
                <OnStartupTriggeringPolicy />
                <SizeBasedTriggeringPolicy size="10 MB"/>
                <TimeBasedTriggeringPolicy />
            </Policies>
        </RollingFile>
    </Appenders>
    <Loggers>
        <AsyncLogger  name="org.jasig" level="info" additivity="false" includeLocation="true">
            <AppenderRef ref="console"/>
            <AppenderRef ref="file"/>
        </AsyncLogger>
        <AsyncLogger  name="org.springframework" level="warn" />
        <AsyncLogger name="org.springframework.webflow" level="warn" />
        <AsyncLogger name="org.springframework.web" level="warn" />
        <AsyncLogger name="org.pac4j" level="warn" />
        <!--
        <AsyncLogger name="org.opensaml" level="debug" additivity="false">
            <AppenderRef ref="console"/>
            <AppenderRef ref="file"/>
        </AsyncLogger>
        <AsyncLogger name="org.ldaptive" level="debug" additivity="false">
            <AppenderRef ref="console"/>
            <AppenderRef ref="file"/>
        </AsyncLogger>
        -->

        <AsyncLogger name="perfStatsLogger" level="info" additivity="false" includeLocation="true">
            <AppenderRef ref="perfFileAppender"/>
        </AsyncLogger>

        <AsyncLogger name="org.jasig.cas.web.flow" level="info" additivity="true" includeLocation="true">
            <AppenderRef ref="file"/>
        </AsyncLogger>
        <AsyncLogger name="org.jasig.inspektr.audit.support" level="info" includeLocation="true">
            <AppenderRef ref="auditlogfile"/>
            <AppenderRef ref="file"/>
        </AsyncLogger>
        <AsyncRoot level="error">
            <AppenderRef ref="console"/>
        </AsyncRoot>
    </Loggers>
</Configuration>

Keepalived+Nginx


做了第一版,重新看了遍手册,发现有几处不对的地方,这里需要改正过来.

操作系统

Centos 7 64位操作系统

安装软件

yum install keepalived

这里说明下,keepalived自带了ipvsadm功能,所以不需要在安装了.

修改sysctl.conf

net.ipv4.ip_forward = 1

关闭防火墙,selinux

Keepalived主配置文件,DR模式

global_defs {
   notification_email {
     1210965963@qq.com
   }
   router_id LVS_HA
}

vrrp_instance VI_1 {
    state BACKUP
    interface enp0s8
    virtual_router_id 51
    priority 90
    advert_int 1
    nopreempt
    authentication {
        auth_type PASS
        auth_pass 1111
    }
    virtual_ipaddress {
        192.168.99.155
    }
}

virtual_server 192.168.99.155 80 {
    delay_loop 1
    lb_algo wrr
    lb_kind DR
    nat_mask 255.255.255.0
    persistence_timeout 50
    protocol TCP

    real_serve 192.168.99.104 80 {
        weight 3
        TCP_CHECK {
            connect_timeout 3
            nb_get_retry 3
            delay_before_retry 3
            connect_port 80
        }
    }

    real_server 192.168.99.105 80 {
        weight 3
        TCP_CHECK {
            connect_timeout 3
            nb_get_retry 3
            delay_before_retry 3
            connect_port 80
        }
    }
}

Keepalived备配置文件

global_defs {
   notification_email {
     1210965963@qq.com
   }
   router_id LVS_HA
}

vrrp_instance VI_1 {
    state LVS_BACKUP
    interface enp0s8
    virtual_router_id 51
    priority 80
    advert_int 1
    nopreempt
    authentication {
        auth_type PASS
        auth_pass 1111
    }
    virtual_ipaddress {
        192.168.99.155
    }
}

virtual_server 192.168.99.155 80 {
    delay_loop 1
    lb_algo wrr
    lb_kind DR
    nat_mask 255.255.255.0
    persistence_timeout 50
    protocol TCP

    real_serve 192.168.99.104 80 {
        weight 3
        TCP_CHECK {
            connect_timeout 3
            nb_get_retry 3
            delay_before_retry 3
            connect_port 80
        }
    }

    real_server 192.168.99.105 80 {
        weight 3
        TCP_CHECK {
            connect_timeout 3
            nb_get_retry 3
            delay_before_retry 3
            connect_port 80
        }
    }
}

Realserver的配置脚本real.sh

#!/bin/bash

VIP=192.168.99.155
ifconfig lo:0 $VIP broadcast $VIP netmask 255.255.255.255 up
echo "1" > /proc/sys/net/ipv4/conf/lo/arp_ignore
echo "2" > /proc/sys/net/ipv4/conf/lo/arp_announce
echo "1" > /proc/sys/net/ipv4/conf/all/arp_ignore
echo "2" > /proc/sys/net/ipv4/conf/all/arp_announce

配置完成,开始进行测试.

操作系统

Centos 7 64位操作系统

安装软件

yum install keepalived
yum install ipvsadm

修改sysctl.conf

net.ipv4.ip_forward = 1

关闭防火墙,selinux

Keepalived主配置文件

global_defs {
   notification_email {
     1210965963@qq.com
   }
   router_id LVS_HA
}

vrrp_instance VI_1 {
    state BACKUP
    interface enp0s8
    virtual_router_id 51
    priority 90
    advert_int 1
    nopreempt
    authentication {
        auth_type PASS
        auth_pass 1111
    }
    virtual_ipaddress {
        192.168.99.155
    }
}

virtual_server 192.168.99.155 80 {
    delay_loop 6
    lb_algo wrr
    lb_kind DR
    nat_mask 255.255.255.0
    persistence_timeout 50
    protocol TCP

    real_serve 192.168.99.104 80 {
        weight 3
        TCP_CHECK {
            connect_timeout 3
            nb_get_retry 3
            delay_before_retry 3
            connect_port 80
        }
    }

    real_server 192.168.99.105 80 {
        weight 3
        TCP_CHECK {
            connect_timeout 3
            nb_get_retry 3
            delay_before_retry 3
            connect_port 80
        }
    }
}

Keepalived备配置文件

global_defs {
   notification_email {
     1210965963@qq.com
   }
   router_id LVS_HA
}

vrrp_instance VI_1 {
    state LVS_BACKUP
    interface enp0s8
    virtual_router_id 51
    priority 80
    advert_int 1
    nopreempt
    authentication {
        auth_type PASS
        auth_pass 1111
    }
    virtual_ipaddress {
        192.168.99.155
    }
}

virtual_server 192.168.99.155 80 {
    delay_loop 6
    lb_algo wrr
    lb_kind DR
    nat_mask 255.255.255.0
    persistence_timeout 50
    protocol TCP

    real_serve 192.168.99.104 80 {
        weight 3
        TCP_CHECK {
            connect_timeout 3
            nb_get_retry 3
            delay_before_retry 3
            connect_port 80
        }
    }

    real_server 192.168.99.105 80 {
        weight 3
        TCP_CHECK {
            connect_timeout 3
            nb_get_retry 3
            delay_before_retry 3
            connect_port 80
        }
    }
}

Keepalived都需要执行的脚本lvs.sh

#!/bin/bash

# 定义虚拟ip
VIP=192.168.99.155
# 定义realserver,并已逗号分开
RIPS=192.168.99.104,192.168.99.105

# 定义提供服务的端口
SERVICE=80

echo "1" > /proc/sys/net/ipv4/conf/all/send_redirects
echo "1" > /proc/sys/net/ipv4/conf/default/send_redirects
echo "1" > /proc/sys/net/ipv4/conf/enp0s8/send_redirects

ifconfig enp0s8:0 $VIP broadcast $VIP netmask 255.255.255.255 up
route add -host $VIP dev enp0s8:0

ipvsadm -C
ipvsadm -A -t $VIP:$SERVICE -s wlc -p
for RIP in `echo $RIPS | sed  -e 's/,/\n/g'`
do
    ipvsadm -a -t $VIP:$SERVICE -r $RIP:$SERVICE -g -w 1
done

ipvsadm --set 30 120 300
ipvsadm

Realserver的配置脚本real.sh

#!/bin/bash

VIP=192.168.99.155
ifconfig lo:0 $VIP broadcast $VIP netmask 255.255.255.255 up
echo "1" > /proc/sys/net/ipv4/conf/lo/arp_ignore
echo "2" > /proc/sys/net/ipv4/conf/lo/arp_announce
echo "1" > /proc/sys/net/ipv4/conf/all/arp_ignore
echo "2" > /proc/sys/net/ipv4/conf/all/arp_announce

每次重启 Keepalived 需要再次执行lvs.sh,另外建议 delay_loop 设置为 1 秒检查一次.

spark安装配置


  • 系统环境:centos7
  • YUM源:http://archive.cloudera.com/cdh5/redhat/7/x86_64/cdh/cloudera-cdh5.repo
  • 最简单的环境安装方式:Cloudera manager

coverage-clover


phpunit tests/ --bootstrap src/autoload.php --coverage-clover reports/phpunit.coverage.xml --log-junit reports/phpunit.xml

注意

记得安装xdebug扩展

PHP运行sonar-runner


产生的错误:

  1. sonar-runner中,需要使用java程序,执行which java时,没有找到java的执行程序.

怀疑是PHP-FPM运行时的环境变量有问题,这里暂时没有深处查找问题源头,直接更改which java为Java执行程序所在的位置.

Redhat Server 优化


1 查看文件数限制,常用命令ulimit,可以用man ulimit查看详细用法

      -a     All current limits are reported
      -b     The maximum socket buffer size
      -c     The maximum size of core files created
      -d     The maximum size of a process's data segment
      -e     The maximum scheduling priority ("nice")
      -f     The maximum size of files written by the shell and its children
      -i     The maximum number of pending signals
      -l     The maximum size that may be locked into memory
      -m     The maximum resident set size (many systems do not honor this limit)
      -n     The maximum number of open file descriptors (most systems do not allow this value to be set)
      -p     The pipe size in 512-byte blocks (this may not be set)
      -q     The maximum number of bytes in POSIX message queues
      -r     The maximum real-time scheduling priority
      -s     The maximum stack size
      -t     The maximum amount of cpu time in seconds
      -u     The maximum number of processes available to a single user
      -v     The maximum amount of virtual memory available to the shell and, on some systems, to its children
      -x     The maximum number of file locks
      -T     The maximum number of threads


      执行ulimit -n查看打开文件的最大数量,默认一般是1024,可以加大此参数.设置为:1024000

修改 /etc/security/limits.conf, 用来控制文件描述符(什么事描述符????->百度),进程数,栈大小.

* soft nofile 1024000 软件限制
* hard nofile 1024000 硬件限制

修改 /etc/security/limits.d/20-nproc.conf,进程限制.

*  soft    nproc     40960

2 网络线程优化,修改 /etc/sysctl.conf,修改内核配置

# 禁用IPV6,如果没有用到的话
net.ipv6.conf.all.disable_ipv6 = 1
net.ipv6.conf.default.disable_ipv6 = 1

# GC时间
net.ipv4.neigh.default.gc_stale_time=120

# ARP配置
net.ipv4.conf.default.arp_announce = 2
net.ipv4.conf.all.arp_announce=2
vm.swappiness = 0
net.ipv4.tcp_max_tw_buckets = 5000
net.ipv4.tcp_max_syn_backlog = 1024
net.ipv4.tcp_synack_retries = 2
net.ipv4.conf.lo.arp_announce=2

net.ipv4.tcp_keepalive_time = 1800
net.ipv4.tcp_keepalive_probes = 3
net.ipv4.tcp_keepalive_intvl = 15

net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_tw_recycle = 1
net.ipv4.tcp_fin_timeout = 30

3 时间校对

cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
# 之后加一个定时任务,定时对时间服务器进行时间校对

4 禁ping

禁止 echo 1 > /proc/sys/net/ipv4/icmp_echo_ignore_all
开启 echo 0 > /proc/sys/net/ipv4/icmp_echo_ignore_all
永久保存 vi /etc/rc.d/rc.local echo 1 >/proc/sys/net/ipv4/icmp_echo_ignore_all

mcrypt_create_iv超时问题


$this->td = mcrypt_module_open(MCRYPT_3DES, '', MCRYPT_MODE_ECB, '');
$this->iv = mcrypt_create_iv(mcrypt_enc_get_iv_size($this->td), MCRYPT_DEV_RANDOM);
$this->ks = mcrypt_enc_get_key_size($this->td);
$this->key = substr(md5($secret_key), 0, $this->ks);

当代码执行到 mcrypt_create_iv 特别缓慢甚至超时。 原因:PHP的Mcrypt扩展的mcrypt_create_iv, 如果你不指定的话, 默认使用/dev/random(Linux上), 作为随机数产生器。 问题就在于/dev/random, 它的random pool依赖于系统的中断来产生. 当系统的中断数不足, 不够产生足够的随机数, 那么尝试读取的进程就会等待, 也就是会hang住。 可以用下面命令测试:

$ dd if=/dev/random bs=1024k count=1

当你的机器不够繁忙的时候, 你会发现, 输出的速度很慢, 偶尔还有停顿.当你20个并发请求的时候, 服务器的中断数不够, 产生不了足够的随机数给mcrypt, 继而导致PHP进程等待, 从而表现出, 响应时间变长.

解决的办法就是, 改用/dev/urandom, /dev/urandom也是一个产生随机数的设备, 但是它不依赖于系统中断.

$this->iv = mcrypt_create_iv(mcrypt_enc_get_iv_size($this->td), MCRYPT_DEV_URANDOM);

不需要修改PHP代码的解决方案

$ rngd -r /dev/urandom -o /dev/random -t 1

用urandom的结果填充entropy池子,这样既保证了entropy池的数量,也保证了随机性. PHP使用/dev/random作为默认, 这是因为理论上来说, /dev/urandom在一定的情况下, 可能会被可预测.所以一般上认为, /dev/urandom不如/dev/random安全.

目录共享权限


挂在虚拟目录的时候,如何指定权限。--Centos7上测试通过

id www 取出uid, gid.
mount -t vboxsf workspace /mnt -o rw,uid=1001,gid=1001

找到一个强人写的万能分类代码,分享一下


function genTree9($items)
{
    $tree = array();
    foreach ($items as $item)
        if (isset($items[$item['pid']]))
            $items[$item['pid']]['son'][] = &$items[$item['id']];
        else
            $tree[] = &$items[$item['id']];
    return $tree;
}

function get_menu_tree($array, $pid = 0)
{
    $arr = array();

    foreach($array as $v){
        if ($v['parent_id'] == $pid) {
            $arr[$v['id']] = $v;
            $arr[$v['id']]['items'] = get_menu_tree($array, $v['id']);
        }
    }

    return $arr;
}