shiroi blog

This is my blog...

简单实现无限极

<?php
function generateTree($array)
{
    //第一步 构造数据
    $items = array();
    foreach ($array as $value) {
        $items[$value['id']] = $value;
    }
    //第二步 遍历数据 生成树状结构
    $tree = array();
    foreach ($items as $key => $item) {
        if (isset($items[$item['pid']])) {
            $items[$item['pid']]['son'][] = &$items[$key];
        } else {
            $tree[] = &$items[$key];
        }
    }
    return $tree;
}
$array = [
    [
        'id' => 1,
        'pid' => 0,
    ],
    [
        'id' => 2,
        'pid' => 1,
    ],
    [
        'id' => 3,
        'pid' => 2,
    ],
    [
        'id' => 4,
        'pid' => 3,
    ],
    [
        'id' => 5,
        'pid' => 4,
    ],
    [
        'id' => 6,
        'pid' => 5,
    ],
    [
        'id' => 7,
        'pid' => 6,
    ],
    [
        'id' => 8,
        'pid' => 7,
    ],
    [
        'id' => 9,
        'pid' => 8,
    ],
    [
        'id' => 10,
        'pid' => 9,
    ],
];
$getTree = generateTree($array);
print_r($getTree);

PHP设计者模式->建造者模式

  1. 一个主体有多个结构(例如小白(一个人):会说多少种语言、肤色、发色、家境、家里多少口人、性格、有木有配偶等等)
  2. 我们就要针对这个人返回这个人的所有结构
  3. 这个人每个结构处理方式不同
  4. 那么我们就要决定这个人究竟是什么人

这里就以卢本伟为案例

/**具体产品角色  人
 * Class Bird
 */
class Person
{
    public $_language;
    public $_skin;
    public $_hair;
    public $_family;
    public $_population;
    public $_nature;
    public $_marriage;
 
    function show()
    {
        echo "会的语言:{$this->_language}<br/>";
        echo "肤色:{$this->_skin}<br/>";
        echo "发色:{$this->_hair}<br/>";
        echo "家境:{$this->_family}<br/>";
        echo "人口:{$this->_population}<br/>";
        echo "性格:{$this->_nature}<br/>";
        echo "婚姻关系:{$this->_marriage}<br/>";
    }
}
 
/**人的建造者(生成器)
 * Class BirdBuilder
 */
abstract class PersonBuilder
{
    protected $_person;
 
    function __construct()
    {
        $this->_person=new Person();
    }
 
    abstract function BuildLanguage();//语言
    abstract function BuildSkin();//肤色
    abstract function BuildHair();//发色
    abstract function BuildFamily();//家境
    abstract function BuildPopulation();//人口
    abstract function BuildNature();//性格
    abstract function BuildMarriage();//婚姻关系
    abstract function GetPerson();//获取人物所有信息
}
 
/**具体人的建造者(生成器)   卢本伟(55开)
 * Class BlueBird
 */
class LuBenWei extends PersonBuilder
{
    function BuildLanguage()
    {
        $this->_person->_language="会骚话、臭嗨话";
    }
 
    function BuildSkin()
    {
        $this->_person->_skin="卢本伟什么肤色都有";
    }
 
    function BuildHair()
    {
        $this->_person->_hair="卢本伟是个光头";
    }
    
    function BuildFamily()
    {
        $this->_person->_family="卢本伟富得流油";
    }
    
    function BuildPopulation()
    {
        $this->_person->_population="卢本伟是个孤儿";
    }
    
    function BuildNature()
    {
        $this->_person->_nature="卢本伟帅的一批、卢本伟不跟你多BB";
    }
    
    function BuildMarriage()
    {
        $this->_person->_marriage="卢本伟有个白富美老婆";
    }
 
    function GetPerson()
    {
        return $this->_person;
    }
}
 
 
/**指挥者
 * Class Director
 */
class Director
{
    /**
     * @param $_builder      建造者
     * @return mixed         产品类:人
     */
    function Construct($_builder)
    {
        $_builder->BuildLanguage();
        $_builder->BuildSkin();
        $_builder->BuildHair();
        $_builder->BuildFamily();
        $_builder->BuildPopulation();
        $_builder->BuildNature();
        $_builder->BuildMarriage();
        return $_builder->GetPerson();
    }
}


$director=new Director();
echo "卢本伟的人物信息:<hr/>";
$lubenwei=$director->Construct(new LuBenWei());
$lubenwei->show();

//执行的结果
卢本伟的人物信息:
会的语言:会骚话、臭嗨话
肤色:卢本伟什么肤色都有
发色:卢本伟是个光头
家境:卢本伟富得流油
人口:卢本伟是个孤儿
性格:卢本伟帅的一批、卢本伟不跟你多BB
婚姻关系:卢本伟有个白富美老婆

PHP设计模式->观察者模式

  1. 观测者模式属于一对多依赖关系
  2. 当一个对象发生改变时,他所依赖的的对象都得到通知
  3. 可以在独立的对象(主体)中维护一个对主体感兴趣的依赖项(观察器)列表
  4. 所有的依赖项(观察器)各自实现公共的ObjectServer接口,取消主体和依赖对象之间的依赖关系

观察者模式应用的场景

  1. 购买商品送优惠券、送商品、送积分、送称号、日志记录
  2. 购火车票要短信通知、日志记录、优惠券赠送

以下就以购买火车票场景编写业务

<?php
/**
 * 观察者模式应用场景实例
 *
 * 免责声明:本文只是以哈票网举例,示例中并未涉及哈票网任何业务代码,全部原创,如有雷同,纯属巧合。
 *
 * 场景描述:
 * 哈票以购票为核心业务(此模式不限于该业务),但围绕购票会产生不同的其他逻辑,如:
 * 1、购票后记录文本日志
 * 2、购票后记录数据库日志
 * 3、购票后发送短信
 * 4、购票送抵扣卷、兑换卷、积分
 * 5、其他各类活动等
 *
 * 传统解决方案:
 * 在购票逻辑等类内部增加相关代码,完成各种逻辑。
 *
 * 存在问题:
 * 1、一旦某个业务逻辑发生改变,如购票业务中增加其他业务逻辑,需要修改购票核心文件、甚至购票流程。
 * 2、日积月累后,文件冗长,导致后续维护困难。
 *
 * 存在问题原因主要是程序的"紧密耦合",使用观察模式将目前的业务逻辑优化成"松耦合",达到易维护、易修改的目的,
 * 同时也符合面向接口编程的思想。
 *
 * 观察者模式典型实现方式:
 * 1、定义2个接口:观察者(通知)接口、被观察者(主题)接口
 * 2、定义2个类,观察者对象实现观察者接口、主题类实现被观者接口
 * 3、主题类注册自己需要通知的观察者
 * 4、主题类某个业务逻辑发生时通知观察者对象,每个观察者执行自己的业务逻辑。
 *
 * 示例:如以下代码
 *
 */
 date_default_timezone_set('PRC'); //设置中国时区
#===================定义观察者、被观察者接口============
/**
 * 观察者接口(通知接口)
 */
interface ITicketObserver //观察者接口
{
  function onBuyTicketOver($sender, $args); //得到通知后调用的方法
}
/**
 * 主题接口
 */
interface ITicketObservable //被观察对象接口
{
  function addObserver($observer); //提供注册观察者方法
}
/**
 *
 * 主题类(购票)
 *
 */
class HipiaoBuy implements ITicketObservable { //实现主题接口(被观察者)
    private $_observers = array (); //通知数组(观察者)
    public function buyTicket($ticket) //购票核心类,处理购票流程
      {
      // TODO 购票逻辑
      //循环通知,调用其onBuyTicketOver实现不同业务逻辑
        foreach ( $this->_observers as $obs )
            $obs->onBuyTicketOver ( $this, $ticket ); //$this 可用来获取主题类句柄,在通知中使用
    }
    //添加通知
    public function addObserver($observer) //添加N个通知
      {
        $this->_observers [] = $observer;
    }
}
#=========================定义多个通知====================
//短信日志通知
class HipiaoMSM implements ITicketObserver {
    public function onBuyTicketOver($sender, $ticket) {
        echo (date ( 'Y-m-d H:i:s' ) . " 短信日志记录:购票成功:$ticket<br>");
    }
}
//文本日志通知
class HipiaoTxt implements ITicketObserver {
    public function onBuyTicketOver($sender, $ticket) {
        echo (date ( 'Y-m-d H:i:s' ) . " 文本日志记录:购票成功:$ticket<br>");
    }
}
  //抵扣卷赠送通知
class HipiaoDiKou implements ITicketObserver {
    public function onBuyTicketOver($sender, $ticket) {
        echo (date ( 'Y-m-d H:i:s' ) . " 赠送抵扣卷:购票成功:$ticket 赠送10元抵扣卷1张。<br>");
    }
}
#============================用户购票====================
$buy = new HipiaoBuy ();
$buy->addObserver ( new HipiaoMSM () ); //根据不同业务逻辑加入各种通知
$buy->addObserver ( new HipiaoTxt () );
$buy->addObserver ( new HipiaoDiKou () );
//购票
$buy->buyTicket ( "一排一号" );

PHP调用trait类

这里定义图片的增删改查trait类

trait HandlePicture
{
    protected static $path = "C:/www";

    private static function add(): string//增
    {
        return self::$add;
    }

    public static function delete(): string//删
    {
        return self::$delete;
    }

    public static function update(): string//改
    {
        return self::$update;
    }

    public static function get(): string//查
    {
        return self::$get;
    }
}

引入图片的trait类

class DB
{
    use HandlePicture;

    public static $add = 'add';

    public static $delete = 'delete';

    public static $update = 'update';

    public static $get = 'get';

    public function __construct(){}

    public function __clone(){}
    
    public function addPicture()
    {
        echo self::add();
    }
}
$addPicture = new DB();//实例化DB类
$addPicture->addPicture();//调用函数

MySQL权限安全总结- 用户权限管理及数据库备份(mysqldump)与恢复

1.安全管理

一、管理用户
mysql的用户账号信息存储在名为mysql的数据库中。
获得所有用户账号列表:

mysql> use mysql;
Database changed
mysql> select user from user;
+-------+
| user  |
+-------+
| root  |
|       |
| cacti |
| root  |
|       |
| root  |
+-------+
6 rows in set (0.00 sec)

mysql>

二、创建用户账号
使用CREATE USER语句:

mysql> create user rokas identified by 'password';
Query OK, 0 rows affected (0.01 sec)

mysql> select user from user;
+-------+
| user  |
+-------+
| rokas |
| root  |
|       |
| cacti |
| root  |
|       |
| root  |
+-------+
7 rows in set (0.00 sec)

mysql>

identified by指定用户密码,省略indentified by语句则为空密码
identified by指定的用户密码为纯文本,在保存到user表之前会对其加密处理。 identified by password 'xxx'则为指定加密过后的密码

三、重命名用户账号(RENAME)
示例:

mysql> rename user rokas to anthony;
Query OK, 0 rows affected (0.00 sec)

mysql>

这仅对于mysql5之后的版本有效。也可以用UPDATE来更新user表,这样对版本无要求。

四、删除用户账号(DROP USER)
删除用户账号(以及权限),使用DROP USER语句:

mysql> drop user anthony;
Query OK, 0 rows affected (0.00 sec)

mysql>

五、设置及撤销访问权限(GRANTREVOKE)
在创建用户账号后,必须接着分配访问权限。不然它们只能登录MySQL,不能看到数据,不能执行任何数据库操作。
为看到赋予用户账号的权限,使用SHOW GRANTS FOR语句:

mysql> create user rokas identified by 'password';
Query OK, 0 rows affected (0.00 sec)

mysql> show grants for rokas;
+------------------------------------------------------------------------------------------------------+
| Grants for rokas@%                                                                                   |
+------------------------------------------------------------------------------------------------------+
| GRANT USAGE ON *.* TO 'rokas'@'%' IDENTIFIED BY PASSWORD '*2470C0C06DEE42FD1618BB99005ADCA2EC9D1E19' |
+------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

mysql>flush privileges;      ###刷新权限

输出结果显示用户rokas有一个权限USAGE ON *.*USAGE表示没有任何权限,所以,此结果表示rokas在任意数据库及表上没有任何权限。
用户定义为user@host
MySQL的权限用用户名和主机名结合定义。如果不指定主机名,则使用默认的主机名%(授予用户访问权限而不管主机名)

示例,创建用户只允许本地登录:

create user 'rokas'@'localhost' identified by 'password';

为设置权限,使用GRANT语句。要求给出以下信息:

mysql> grant select on crashcourse.* to rokas;
Query OK, 0 rows affected (0.01 sec)

mysql>flush privileges;

GRANT允许用户在crashcourse.*(crashcourse数据库所有表)上使用SELECT
通过只授予SELECT访问权限,用户rokascrashcourse数据库中的所有数据具有只读访问权限。

显示这个更改:

mysql> show grants for rokas;
+------------------------------------------------------------------------------------------------------+
| Grants for rokas@%                                                                                   |
+------------------------------------------------------------------------------------------------------+
| GRANT USAGE ON *.* TO 'rokas'@'%' IDENTIFIED BY PASSWORD '*2470C0C06DEE42FD1618BB99005ADCA2EC9D1E19' |
| GRANT SELECT ON `crashcourse`.* TO 'rokas'@'%'                                                       |
+------------------------------------------------------------------------------------------------------+
2 rows in set (0.00 sec)

mysql>

GRANT的反操作为REVOKE,用来撤销特定权限,示例:

mysql> revoke select on crashcourse.* from rokas;
Query OK, 0 rows affected (0.00 sec)

mysql> flush privileges;

这条语句撤销用户rokascrashcourse数据库的SELECT访问权限。

GRANTREVOKE可在以下几个层次上控制访问权限:

权限说明
ALLGRANT OPTION外的所有权限
ALTER使用ALTER TABLE
ALTER ROUTINE使用ALTER PROCEDUREDROP PROCEDURE
CREATE使用CREATE TABLE
CREATE ROUTINE使用CREATE PROCEDURE
CREATE TEMPORARY使用CREATE TEMPORARY TABLE
CREATE USER使用CREATE USERDROP USERRENAME USERREVOKE ALL PRIVILEGES
CREATE VIEW使用本身
DELETE使用本身
DROP使用DROP TABLE
EXECUTE使用CALL和存储过程
FILE使用SELECT INTO OUTFILELOAD DATA INFILE
GRANT OPTION使用GRANTREVOKE
INDEX使用CREATE INDEXDROP INDEX
INSERT使用本身
LOCK TABLES使用本身
PROCESS使用SHOW FULL PROCESSLIST
RELOAD使用FLUSH
REPLICATION CLIENT服务器位置的访问
REPLICATION SLAVE由复制从属使用
SELECT使用本身
SHOW DATABASES使用本身
SHOW VIEW使用SHOW CREATE VIEW
SHUTDOWN使用mysqladmin shutdown(用于关闭MySQL)
SUPER使用CHANGE MASTERKILLLOGSPURGEMASTERSET GLOBAL。还允许mysqladmin调试登录
UPDATE使用本身
USAGE无访问权限

根据上表配合GRANTREVOKE,可以完全控制用户权限。

如果有多个权限,可以用逗号分隔:

GRANT SELECT,INSERT ON crashcourse.* to rokas;

注意:在使用GRANTREVOKE时,用户账号必须存在,而涉及的对象没有要求。这允许管理员在创建数据库和表之前设计和实现安全控制。

六、更改密码(SET PASSWORD)
更改用户密码,使用SET PASSWORD语句。
示例:

mysql> set password for rokas=password('new password');
Query OK, 0 rows affected (0.00 sec)

mysql> flush privileges;
Query OK, 0 rows affected (0.00 sec)

mysql>

set password更新用户密码,新密码必须传递到Password函数进行加密。

设置当前用户的口令:

mysql> set password=password('123456');
Query OK, 0 rows affected (0.00 sec)

mysql> flush privileges;
Query OK, 0 rows affected (0.00 sec)

mysql>

2.数据库备份及维护

一、数据库备份及还原(mysqldump)
1)备份

格式:

mysqldump -h主机名 -P端口 -u用户名 -p密码(后不跟密码则会交互输入密码) --database 数据库名 >文件名.sql

示例:

mysqldump -hlocalhost -P3306 -uroot -p --database www >www.bak.sql
mysqldump --all-databases > allbackupfile.sql
mysqldump -hhostname -uusername -ppassword -database databasename | gzip > backupfile.sql.gz

2)还原
格式:mysql -h主机名 -u用户名 -p密码 <文件名.sql

示例:

mysql -hlocalhost -uroot -p123456 <www.bak.sql

或者使用source:

mysql>use mysql;
mysql>source test.sql;
zcat bakupfile.sql.gz | mysql -uuser -ppassword

二、确保数据库正确及正常运行,使用以下语句来检查健康状态

1)ANALYZE TABLE,用来检查表键是否正确

示例:

mysql> analyze table orders;
+---------------+---------+----------+----------+
| Table         | Op      | Msg_type | Msg_text |
+---------------+---------+----------+----------+
| course.orders | analyze | status   | OK       |
+---------------+---------+----------+----------+
1 row in set (0.00 sec)

mysql>

2)CHECK TABLE用来针对许多问题对表进行检查。
示例:

mysql> check table orders,orderitems;
+-------------------+-------+----------+----------+
| Table             | Op    | Msg_type | Msg_text |
+-------------------+-------+----------+----------+
| course.orders     | check | status   | OK       |
| course.orderitems | check | status   | OK       |
+-------------------+-------+----------+----------+
2 rows in set (0.00 sec)

mysql>

如果MyISAM引擎的表产生不正确和不一致的结果,可能需要用REPAIR TABLE来修复相应的表。但不应该经常使用,可能会造成更大的问题要解决。

3)OPTIMIZE TABLE
如果从一个表中删除大量数据,应该使用OPTIMIZE TABLE来收回所用空间,优化表的性能。
示例:

mysql>optimize table orders;

三、诊断启动问题
在排除系统启动问题时,首先应该尽量手动启动服务器。MySQL服务器自身通过在命令行上执行mysqld启动,下面是几个重要的mysqld命令行选项:
--help 显示帮助
--safe-mode装载减去某些最佳配置的服务器
--verbose显示全文本消息(为获得更详细的帮助消息与--help联合使用)
--version显示版本信息

四、查看日志文件
MySQL主要日志文件有以下几种:

  1. 错误日志。包含启动和关闭问题以及任意关键错误的细节。此日志通常名为hostname.err(可用--log-error命令行选项更改),位于data目录中。
  2. 查询日志。记录所有mysql活动,在诊断问题时非常有用。此日志通常名为hostname.log(可用--log命令行选项更改),位于data目录。
  3. 二进制日志。记录更新过数据(或者可能更新过数据)的所有语句,名为hostname-bin(可用--log-bin命令行选项更改),位于data目录。
  4. 缓慢查询日志。此日志记录执行缓慢的任何查询,名为hostname-slow.log(用--log-slow-queries选项更改)

在使用日志时,可用FLUSH LOGS语句来刷新和重新开始所有日志文件。

备案号:粤ICP备18155514号-2