最新消息:XAMPP默认安装之后是很不安全的,我们只需要点击左方菜单的 "安全"选项,按照向导操作即可完成安全设置。

PHP开发者_当CPU飙升时,发现PHP中可能有问题的代码行

XAMPP新闻 admin 18浏览 0评论

根据不同的权限,在菜单栏显示不同的功能,只对菜单进行了限制,若对路由也进行限制,可以根据菜单的示例,请自行完善,开发。下面请认真学习一下laravel的RBAC设计

 

1,建表(用户表,角色表,权限表,用户角色表,角色权限表)

CREATE  TABLE  IF  NOT  EXISTS  mr_role

ID  INT11)PRIMARY  KEY  AUTO_INCREMENT  COMMENT  ‘自增ID’
名称 VARCHAR30)  NOT  NULL  COMMENT  ‘角色名’
ENGINE = innodb的 DEFAULT  CHARSET = UTF8  COMMENT = ‘角色表’ ; CREATE  TABLE  IF  NOT  EXISTS  mr_privilege

ID  INT11)PRIMARY 密钥  AUTO_INCREMENT  COMMENT  ‘自增ID’
名称 varchar30)  NOT  NULL  COMMENT  ‘权限名’
路由varchar50)  NOT  NULL  COMMENT  ‘权限所有的路由 
描述  varchar100)  NOT  NULL  COMMENT  ‘权限的描述’
ENGINE = innodb  DEFAULT  CHARSET = utf8  COMMENT = ‘权限表’ ; 如果创建    EXISTS  mr_user_role

id  int11)主   AUTO_INCREMENT  COMMENT  ‘自增id’
user_id  int11)    COMMENT  ‘用户id’
role_id  int11)    COMMENT  ‘角色ID’
ENGINE = innodb  默认 字符集 = utf8  COMMENT = ‘用户角色表’ ; CREATE  TABLE  IF  NOT  EXISTS mr_role_privilege

id  int11)主   AUTO_INCREMENT  COMMENT  ‘自增id’
role_id  int11)  NOT  NULL  COMMENT  ‘角色ID’
privilege_id  int11)  NOT  NULL  COMMENT  ‘权限id’
ENGINE = innodb  默认 字符集 = utf8  COMMENT = ‘角色权限表’ ;

 

2,在用户模型和角色模型中实现多对多

 用户 扩展 模型
{
protected  $ primaryKey =  ‘id’ ;
protected  $ table =  ‘用户’ ;
public  $ timestamps =  false ;
公共  $ guarded = [];
公共 功能 角色()
{
return  $ this-> belongsToMany( ‘App \ Model \ Role’,  ‘user_role’,  ‘user_id’,  ‘role_id’)-> withPivot( ‘user_id’,  ‘role_id’);
  }
}

 

class  Role  扩展了 模型
{
protected  $ table =  ‘role’ ;
保护  $ primaryKey =  ‘id’ ;
public  $ timestamps =  false ;
公共  $ guarded = [];
公共 功能 特权()
{
返回 $ this-> belongsToMany( ‘App \ Model \ Privilege’,  ‘role_privilege’,  ‘role_id’,  ‘privilege_id’)-> withPivot([ ''role_id',  'privilege_id' ]);
  }
}

 

3,将菜单视为公共区域,在app \ Providers \ AppServiceProvider.php里写

公共 功能 启动()
{
    \ View :: composer(‘layout.slide’,  功能($ view)  {
      $ roles_id = User :: find(session(‘user’)[ 'id' ])-> roles-> map (function  ($ role)  {
return  $ role-> id;
      });   //使用映射,最终得到的结果$ roles_id = [1,2,...]
      $ privileges = [];
foreach  ($ roles_id as $角色){
        $ privileges = array_merge($ privileges,Role :: find($ role)-> privileges-> map(function  ($ privilege)  {
返回  [$ privilege-> name,$ privilege-> route];
        })-> toArray());
      }   //得到的结果,$ prpvileges = [[''index / ..','列表'],['','']]
      $ view-> with(‘privileges’,$ privileges);
    });
}

 

4,菜单的实现(可以直接遍历一个div,我这里因为有不同的样式,便用了判断)

@foreach($ privileges  作为  $ privilege)
      @ if  ($ privilege [ 1 ] ==  ‘键/索引’  && $ privilege [ 0 ] ==  ‘键名列表’
        <div  class = “ slide__left__key”  style = “ margin-顶部:10像素;” > < 一个 HREF = “{{URL( ‘键/索引’)}}”  的rel = “外部nofollow的”  > < 跨度  = “glyphicon glyphicon个” > </ 跨度 >  键名列表<div >
      @endif
      @ if  ($ privilege [ 1 ] ==  ‘key / create’  && $ privilege [ 0 ] ==  ‘添加键名’
          <div  class = “ slide__left__key” > < a  href = “ {{url( ‘key / create’)}}“”  rel = “ external nofollow”  > < span  class = “ glyphicon glyphicon-plus” > </ span >  添加键名</ a > </ div >
      @endif
      @if  ($ privilege [ 1 ] ==  ‘项目/索引’  && $ privilege [ 0 ] ==  ‘项目列表’
          <div  class = “ slide__left__key”  style = “ margin-top:20px;” > < 一个 HREF = “{{URL( ‘项目/索引’)}}”  的rel = “外部nofollow的”  > < 跨度  = “glyphicon glyphicon个清单” > </ 跨度 >  项目列表</ > < ($ privilege [ 1 ] ==  ‘project / create’  && $ privilege [ 0 ] ==  ‘添加项目’
          <div  class = “ slide__left__key” > < a  href = “ {{url(’project / create’)}} }“  rel = ” external nofollow“  > < span  class = ” glyphicon glyphicon-edit“ > </ span >  添加项目</ a > </ div >
      @endif
      @ if  ($ privilege [ 1 ] == “’user / index’  && $ privilege [ 0 ] ==  ‘用户列表’
          <div  class = ” slide__left__key“  style = ” margin-top:20px;“ > < 一个 HREF = “{{URL( ‘用户/索引’)}}”  的rel = “外部nofollow的”  > < 跨度  = “glyphicon glyphicon-TH-大” > </ 跨度 >  用户列表</ > < / div >‘user / create’  && $ privilege [ 0 ] ==  ‘添加用户’
          <div  class = “ slide__left__key” > < a  href = “ {{url(’user / create’)}}”  rel = “外部nofollow”  > < span  class = “ glyphicon glyphicon-plus-sign” > </ span >  添加用户</ a > </ div >
      @endif
@endforeach 

当您发现一个平时占用cpu比较少的进程突然间占用cpu接近100%时,您如何找到导致cpu飙升的原因?我的思路是,首先找到进行中正在执行的代码行,从而确定可能有问题的代码段。然后,再仔细分析有问题的代码段,从而找到原因。

 

如果,您的程序使用的是c,c ++编写,那么您可以很容易的找到正在执行的代码行。但是,程序是php编写的,如何找到可能有问题的代码行呢?这个问题就是此处要解决的问题。

 

背景知识:

 

如果您对c语言不熟悉的话,可以略过,直接看样品演示。

 

用户编写的php代码会生成opcode,由解释器引擎去解释执行。在解释执行过程中,有一个变量包含了执行过程中用到的各种数据。它就是executor_globals。在原始码的Zend / zend_globals.h文件中可以找到他的类型定义。

 

struct _zend_executor_globals {

zval ** return_value_ptr_ptr;

 

zval uninitialized_zval;

zval * uninitialized_zval_ptr;

 

zval error_zval;

zval * error_zval_ptr;

 

zend_ptr_stack arg_types_stack;

 

/ *符号表缓存* /

哈希表* symtable_cache [SYMTABLE_CACHE_SIZE];

哈希表** symtable_cache_limit;

哈希表** symtable_cache_ptr;

 

zend_op ** opline_ptr;

 

哈希表* active_symbol_table;

    哈希表symbol_table; / *主符号表* /

 

    HashTable included_files; / *已包含文件* /

 

JMP_BUF *救援;

 

int error_reporting;

int orig_error_reporting;

int exit_status;

 

zend_op_array * active_op_array;

 

    哈希表* function_table; / *功能符号表* /

    哈希表* class_table; / *类表* /

    哈希表* zend_constants; / *常数表* /

 

zend_class_entry *作用域;

    zend_class_entry * named_scope; / *调用类的范围* /

 

zval *这;

 

精度高;

 

int ticks_count;

 

zend_bool in_execution;

哈希表* in_autoload;

zend_function * autoload_func;

zend_bool full_tables_cleanup;

 

/ *用于扩展信息支持* /

zend_bool no_extensions;

 

#ifdef ZEND_WIN32

zend_bool timed_out;

OSVERSIONINFOEX windows_version_info;

#万一

 

HashTable normal_list;

HashTablepersistent_list;

 

zend_vm_stack arguments_stack;

 

int user_error_handler_error_reporting;

zval * user_error_handler;

zval * user_exception_handler;

zend_stack user_error_handlers_error_reporting;

zend_ptr_stack user_error_handlers;

zend_ptr_stack user_exception_handlers;

 

zend_error_handling_t error_handling;

zend_class_entry * exception_class;

 

/ *超时支持* /

int timeout_seconds;

 

int lambda_count;

 

哈希表* ini_directives;

哈希表* modified_ini_directives;

 

zend_objects_store objects_store;

zval * exception,* prev_exception;

zend_op * opline_before_exception;

zend_op exception_op [3];

 

struct _zend_execute_data * current_execute_data;

 

struct _zend_module_entry *当前模块;

 

zend_property_info std_property_info;

 

zend_bool活动;

 

无效* saved_fpu_cw;

 

*已保留无效[ZEND_MAX_RESERVED_RESOURCES];

};

 

这里我们只说两个对我们比较重要的变量,active_op_array和current_execute_data。

 

active_op_array变量中保存了引擎正在执行的op_array(想了解什么是op_array请点击查看)。在Zend / zend_compile.h中有关于op_array的数据类型的定义。

 

struct _zend_op_array {

/ *通用元素* /

zend_uchar类型;

字符* function_name;

zend_class_entry *作用域;

zend_uint fn_flags;

union _zend_function * prototype;

zend_uint num_args;

zend_uint required_num_args;

zend_arg_info * arg_info;

zend_bool pass_rest_by_reference;

unsigned char return_reference;

/ *共同元素的结尾* /

 

zend_bool done_pass_two;

 

zend_uint *引用计数;

 

zend_op *操作码;

zend_uint最后,大小;

 

zend_compiled_variable * vars;

int last_var,size_var;

 

zend_uint T;

 

zend_brk_cont_element * brk_cont_array;

int last_brk_cont;

int current_brk_cont;

 

zend_try_catch_element * try_catch_array;

int last_try_catch;

 

/ *静态变量支持* /

哈希表* static_variables;

 

zend_op * start_op;

int backpatch_count;

 

zend_uint this_var;

 

char *文件名;

zend_uint line_start;

zend_uint line_end;

char * doc_comment;

zend_uint doc_comment_len;

    zend_uint early_binding; / *延迟声明的链接列表* /

 

*已保留无效[ZEND_MAX_RESERVED_RESOURCES];

};

 

看完定义,就不用我多说了把。定义中,文件名和function_name分别保存了正在执行的文件名和方法名。

 

current_execute_data保存了正在执行的op_array的execute_data。execute_data保存了每个op_array执行过程中的一些数据。其定义在,Zend / zend_compile.h:

 

struct _zend_execute_data {

struct _zend_op * opline;

zend_function_state function_state;

    zend_function * fbc; / *被调用的函数* /

zend_class_entry * named_scope;

zend_op_array * op_array;

zval * object;

union _temp_variable * Ts;

zval *** CV;

哈希表* symbol_table;

struct _zend_execute_data * prev_execute_data;

zval * old_error_reporting;

zend_bool嵌套;

zval ** original_return_value;

zend_class_entry * current_scope;

zend_class_entry * current_drawn_scope;

zval * current_this;

zval * current_object;

struct _zend_op * call_opline;

};

 

定义中的opline就是正在执行的opcode。opcode的结构定义如下:

 

struct _zend_op {

opcode_handler_t处理程序;

znode结果;

znode op1;

znode op2;

ulong extended_value;

uint lineno;

zend_uchar操作码;

};

 

其中lineno就是opcode所对应的行号。

 

示例说明:

 

看完上面的数据结构定义,你是否已经知道如何找php正在执行的文件名,方法名和行号呢?如果还有疑问的话,那就接着看下面的例子。创建一个文件test.php,代码如下:

 

<?php

函数test1(){

while(true){

睡眠(1);

}

}

test1();

?>

 

cli方法执行php脚本,加入执行的进程号为14973。我们使用gdb命令来调试进程。

 

$ sudo gdb -p 14973

(gdb)打印(char *)executor_globals.active_op_array->文件名

$ 1 = 0x9853a34“ /home/xinhailong/test/php/test.php”

(gdb)打印(char *)executor_globals.active_op_array-> function_name

$ 2 = 0x9854db8“ test1”

(gdb)打印executor_globals-> current_execute_data-> opline-> lineno

$ 3 = 4

 

很明显,他正在执行第四行的睡眠方法。

 

如果上面的方法你感觉麻烦,那你可以使用.gdbinit文件。这个文件在php源码的根目录下。使用方法如下:

 

$ sudo gdb -p 14973

(gdb)源/home/xinhailong/.gdbinit

(gdb)zbacktrace

[0xa453f34] sleep(1)/home/xinhailong/test/php/test.php:4

[0xa453ed0] test1()/home/xinhailong/test/php/test.php:7

(gdb)

 

题外话:

 

从PHP5.6开始,PHP中集成了一个phpdbg的工具。可以像gdb调试c语言程序一样,调试PHP程序。发现的话,可以打开下面的连接看看。

转载请注明:XAMPP中文组官网 » PHP开发者_当CPU飙升时,发现PHP中可能有问题的代码行