1.python的变量
py的变量大部分与php的类似,只是py的常亮有所不同,PI = 3.1415926,这是一个常量,但只是py习惯的把全部大写的变量叫常量,实质上还是变量,你想改变他的值也没人拦着你。PY是和php一样都是动态语言,定义变量时不用定义变量类型,而java是静态语言,定义变量时必须定义变量的类型,否则会报错。
py中的字符串类型的变量想要输出多行的时候只需用6个单引号括起来即可,即
print(”’
line1
line2
line3
);
2.python的运算
py的运算除法有些不同,/是精确运算,//是取整运算,%是获得余数的运算
3.python变量的赋值
a = 10是现在内存中创建一个10的整数,然后再创建一个名字叫a的变量,将变量a指向10
b = a 是在内存中创建一个b的变量,将b的变量指向a的变量指向的数据,也就是整数10
4.py的运行模式
py的运行模式有两种:交互模式和命令行模式
直接在cmd中输入python进入交互模式,交互模式一行行执行代码
python XXX.py 执行一个py文件,将文件中的代码一次性的执行完成
在python中整数和字符串都是不可变对象,这是什么意思呢?
a = ‘abc’,变量a赋值为字符串’abc’,b = a.replace(‘a’,’A’); 变量b对应的值是Abc,当我们输出a的时候,a的值还是abc,这是因为abc是不可变对象,a是指向abc的,所以a并没有被改变,b变量是把a变量对应的对象a变成A后创建了一个新的对象,是Abc,b指向了Abc
最后:python是动态语言,区分大小写的!
PHP编程语言于1995年首次发布,23年后,仍然有成百上千的网站开发人员无法理解这样一个基本概念:调试和错误报告消息可能包含导致黑客攻击的信息,永远不应该在实时网站上激活这些信息。
根据网络安全公司Hacken网络风险研究总监Bob Diachenko的说法,今天这个问题依旧存在。
Diachenko在互联网上搜索了一些用Laravel(用于构建web应用程序的PHP框架)编写的网站,这些网站正在调试模式暴露敏感信息。
“我已经提出了566个IP的惊人列表,”Diachenko 今天发表的研究报告中说。
Laravel调试模式中包含的信息取决于网站或Web应用程序使用的框架功能,从源代码的基本提示到调试信息的位置,以及调试信息在高度敏感的数据库和API证书上的位置。
“这些信息可能有助于攻击者获取更多信息,有可能专注于对目标系统的进一步攻击,”Diachenko说。
显然,最危险的案例是通过Laravel的调试模式消息以明文形式打印数据库和API凭证的网站。
“在过去的两周里,我已经负责地通知了22家公司”Diachenko说。
在Diachenko最近的一项研究中突出支出的一件事就是PrestoDaycare,这是瑞典的一家公司,主要负责开发基于网络的育儿平台。
该公司的网络服务允许教师,学前教职员工,经理和家长可以通过一个基于web的控制面板管理、参与和关注学前活动。但上个月,Diachenko发现通过Laravel的调试模式泄露了大量敏感细节,该模式目前仍在使用。
该网站泄露了黑客访问其服务器并下载有关儿童看护设施、儿童及其父母的敏感数据所需的一切信息。
Diachenko与该公司取得联系,在瑞典当地安全研究人员和瑞典计算机应急研究小组(CERT)的帮助下,PrestoDaycare接到了通知,目前该网站停用了调试模式。该公司还否认他们故意启用了调试模式,此次事件只是因为一个bug导致。
Diachenko说,在他通知的22家公司中,有5家尚未回复他的电子邮件,并且仍在通过调试消息泄露敏感数据。
不用多说,无论是Apache,PHP,Java,JavaScript还是其他技术,都不应该在生产环境上持续启用调试模式。
php有很多开源的框架。但是各个框架也有不同之处。本人认为:初学php框架,首先推荐thinkphp,网上搜搜的资料比较多、易学,简单
1. zendframework zend php语言公司发布的官方框架,重量级(功能多)
2. yii 美国华人开发的框架,xue qiang, qiang, 重量级框架,纯OOP框架
3. CI CodeIgniter 轻量级框架,开发速度快,部署灵活
4. cakephp 外国框架,重量级,速度慢
5. symfony 外国重量级框架
6. ThinkPHP 轻量级框架,国人框架,入门容易
总体来讲:thinkphp入口到执行完成需要涉及到的几个文件如下:
Index.php
ThinkPHP.php
Think.class.php
App.class.php
Dispatcher.class.php
ThinkPHP/Mode/common.php
ReadHtmlBehavior.class.php
Route.class.php
Hook.class.php
ContentReplaceBehavior.class.php
WriteHtmlCacheBehavior.class.php
ThinkPHP框架开发的应用的标准执行流程如下:用户URL请求调用应用入口文件public目录下(通常是网站的index.php)载入框架入口文件(ThinkPHP.php)在php5.3版本以后设置常量有两种方式:const name = value; 作用域根据当前命名空间决定define() 作用域全局① 定义了许多常量② 引入核心文件Think.class.phpThink::start();系统常量判断及定义(引用自ThinkPHP.php)// 系统常量定义
defined('THINK_PATH') or define('THINK_PATH', __DIR__.'/');
defined('APP_PATH') or define('APP_PATH', dirname($_SERVER['SCRIPT_FILENAME']).'/');
defined('APP_STATUS') or define('APP_STATUS', ''); // 应用状态 加载对应的配置文件defined('APP_DEBUG') or define('APP_DEBUG', false); // 是否调试模式
6 载入框架引导类(Think\Think)并执行Think::start方法进行应用初始化
Think\Think::start();
7 设置错误处理机制和自动加载机制
spl_autoload_register('Think\Think::autoload');
// 设定错误和异常处理
register_shutdown_function('Think\Think::fatalError');
set_error_handler('Think\Think::appError');
set_exception_handler('Think\Think::appException');
8 调用Think\Storage类进行存储初始化
(引用Think.class.php)
// 初始化文件存储方式
Storage::connect(STORAGE_TYPE);
9 部署模式下如果存在应用编译缓存文件则直接加载
if(!APP_DEBUG &&Storage::has($runtimefile)){
Storage::load($runtimefile);
}
10 读取应用模式(由APP_MODE常量定义)的定义文件
// 读取应用模式
$mode = include is_file(CONF_PATH.'core.php')?CONF_PATH.'core.php':MODE_PATH.APP_MODE.'.php';
ThinkPHP/Library/Think/Think.class.php
static function start()
① 引入系统核心文件
② 引入配置文件
③ 如果是生成模式,还会生成common~runtime.php文件
④ 如果是第一次使用系统,还会自动创建对应的应用目录
App::run();
路由解析
//路由解析_把模块_控制器_方法赋予常量
//MODULE_NAME = 模块名称
//CONTROLLER_NAME 控制器
//ACTION_NAME 方法
App::exec()
实例化控制器对象
利用“反射”实现对象调用方法
11 加载应用配置文件(普通模式是 Application/Common/Conf/config.php)
12. 加载框架底层语言包(普通模式是 ThinkPHP/Lang/zh-cn.php)13. 如果是部署模式则生成应用编译缓存文件14. 加载调试模式系统配置文件(ThinkPHP/Conf/debug.php)15. 判断并读取应用的调试配置文件(默认是 Application/Common/Conf/debug.php)16 检测应用目录结构并自动生成(如果CHECK_APP_DIR配置开启并且RUNTIME_PATH目录不存在的情况下)
17 应用初始化(app_init)标签位侦听并执行绑定行为18. 判断并加载动态配置和函数文件19. 调用Think\Dispatcher::dispatch方法进行URL请求调度
20 获取请求的模块信息21. 检测模块是否存在和允许访问22. 判断并加载模块配置文件、别名定义、行为定义及函数文件23. 判断并加载模块的动态配置和函数文件24. 模块的URL模式判断25. 模块的路由检测(URL_ROUTER_ON开启)
26 根据请求执行控制器方法27. 如果控制器不存在则检测空控制器是否存在28. 控制器开始(action_begin)标签位侦听并执行绑定行为
29 判断并调用控制器的_initialize初始化方法
30 视图开始(view_begin)标签位侦听并执行绑定行为31. 调用Think\View的fetch方法解析并获取模版内容
0X00 安装模式
在PHP中有以下几种常见的安装模式:
1. CGI模式
CGI是通用网关接口,HTTP服务器使用这样的接口程序来调用外部程序,外部程序可以使用任何计算机语言来编写,例如C,C++,Perl,Visual Basic,Shell等等,历史上用来编写CGI程序使用最广泛的是Perl语言。
服务器在认为这是一个CGI请求时,会调用相关CGI程序,并通过环境变量和标准输出将数据传送给CGI程序,CGI程序处理完数据,生成html,然后再通过标准输出将内容返回给服务器,服务器再将内容交给用户浏览器,CGI进程退出。
CGI的出现让WEB从静态变为为动态,随着Web的越来越普及,很多的网站的都需要有动态的页面,以便与浏览者互交。CGI方式的缺点也越来越突出。因为HTTP要生成一个动态页面,系统就必须启动一个新的进程以运行CGI程序,CGI采用fork and execution方式,每次请求都需要新建立CGI程序来进行处理,不断地fork是一项很消耗时间和资源的工作,导致性能的低下。这就出现了FastCGI。
2. FastCGI模式
FastCGI是从CGI发展改进而来的。传统CGI接口方式的主要缺点是性能很差,因为每次HTTP服务器遇到动态程序时都需要重新启动脚本解析器来执行解析,然后结果被返回给HTTP服务器。这在处理高并发访问时,几乎是不可用的。另外传统的CGI接口方式安全性也很差,现在已经很少被使用。FASTCGI快速通用网关接口是常驻内存的CGI,实际上是对CGI程序的进程管理,FastCGI接口方式采用C/S结构,可以将HTTP服务器和脚本解析服务器分开,同时在脚本解析服务器上启动一个或者多个脚本解析守护进程。当HTTP服务器每次遇到动态程序时,可以将其直接交付给FastCGI进程来执行,然后将得到的结果返回给浏览器。这种方式可以让HTTP服务器专一地处理静态请求或者将动态脚本服务器的结果返回给客户端,这在很大程度上提高了整个应用系统的性能。
相关的Fastcgi学习可到合天网安实验室操作实验——Fastcgi安全:本实验介绍了fastcgi安全,是以nginx+php+fastcgi为环境,在多台fastcgi服务器做负载均衡的情况下,容易出现的错误。
3. Module模式
Module模式就是把php作为apache的一个子模块来运行,使用LoadModule来加载php模块,比如在apache的配置文件中
//httpd.confLoadModule php7_module "${INSTALL_DIR}/bin/php/php7.2.13/php7apache2_4.dll"
当web访问php文件时,apache会调用php模块来解析,phpmodule通过sapi来把数据传递给php解析器进行解析。
4. PHP-FPM模式
最后是本篇文章的主角PHP-FPM,FPM是一个FastCGI协议解析器,Nginx等服务器中间件将用户请求按照FastCGI的规则打包好发送给PHP-FPM,再由PHP-FPM来将打包的数据进行解析并与FastCGI进行通信,PHP-FPM就是为了实现和管理FastCGI协议的进程(fastcgi进程管理器),管理一个进程池,处理来自于web服务器的请求。其中,Ngnix与PHP-FPM有两种通信方式,分别是TCP与Unix domain sockets模式。在windows系统中只能使用tcp socket的通信方式。
TCP模式
TCP模式是PHP-FPM进程监听本机上端口(默认为9000),Ngnix将用户请求按照fastcgi的规则打包好发送给php-fpm,由PHP-FPM调用cgi进行解析。TCP通信模式允许通过网络进程之间的通信,也可以通过loopback进行本地进程之间通信。
Unix domain sockets模式
Unix socket 又叫 IPC (inter-process communication 进程间通信) socket,用于实现同一主机上的进程间通信,这种方式需要在 Ngnix配置文件中填写 PHP-FPM 的 socket 文件位置。
在P神的Fastcgi协议分析 && PHP-FPM未授权访问漏洞 && Exp编(https://www.leavesongs.com/PENETRATION/fastcgi-and-php-fpm.html)写这篇文章中对其中的原理已经做了比较详细的解释:
假如用户访问
http://127.0.0.1/index.php?a=1&b=2
如果web 目录为/var/www/html,Nginx将请求变成键值对
{
'GATEWAY_INTERFACE': 'FastCGI/1.0',
'REQUEST_METHOD': 'GET',
'SCRIPT_FILENAME': '/var/www/html/index.php',
'SCRIPT_NAME': '/index.php',
'QUERY_STRING': '?a=1&b=2',
'REQUEST_URI': '/index.php?a=1&b=2',
'DOCUMENT_ROOT': '/var/www/html',
'SERVER_SOFTWARE': 'php/fcgiclient',
'REMOTE_ADDR': '127.0.0.1',
'REMOTE_PORT': '12345',
'SERVER_ADDR': '127.0.0.1',
'SERVER_PORT': '80',
'SERVER_NAME': "localhost",
'SERVER_PROTOCOL': 'HTTP/1.1'
}
这个数组其实就是PHP中$_SERVER数组的一部分,也就是PHP里的环境变量。其作用不仅是填充$_SERVER数组,也是在告诉FPM要执行哪个PHP文件。当PHP-FPM拿到了数据包在之后,进行解析,得到了环境变量,然后执行SCRIPT_FILENAME的值指向的PHP文件,即/var/www/html/index.php。
0X01 如何利用
PHP-FPM默认监听9000端口,如果这个端口暴露在公网,则我们可以自己构造FastCGI协议,和FPM进行通信。这时候可以利用SCRIPT_FILENAME来指定执行php文件,如果文件不存在则返回404。在Nginx中存在一个配置限定了只有带某些后缀的文件才允许被PHP-FPM执行,默认为.php,security.limit_extensions
; Limits the extensions of the main script FPM will allow to parse. This can
; prevent configuration mistakes on the web server side. You should only limit
; FPM to .php extensions to prevent malicious users to use other extensions to
; exectute php code.
; Note: set an empty value to allow all extensions.
; Default Value: .php
;security.limit_extensions = .php .php3 .php4 .php5 .php7
为了避免404,首先需要找到已存在的PHP文件,如果不知道web的绝对路径或者web目录下的php文件名,可以使用全局搜索得到环境中默认的php文件。
find / -name "*.php"
在我们获得一个webshell的时候,怎么能突破限制执行任意PHP代码呢?
首先我们能控制
SCRIPT_FILENAME
,让fpm执行的任意文件,但是也只是执行目标服务器上的文件,并不能执行我们需要其执行的文件,但是在PHP中有很多有趣的技巧,比如在php.ini中有两个配置项
auto_prepend_file //在执行目标文件之前,先包含auto_prepend_file中指定的文件
auto_append_file //在执行完成目标文件后,包含auto_append_file指向的文件
如果设置auto_prepend_file为php://input,则相当于执行任何php文件之前会包含$_POST中的内容,使用php://input需要开启远程文件包含(allow_url_include)。
在PHP-FPM中还会解析两个环境变量
PHP_VALUE //用于设置PHP的配置项,除 disable_function 以外的大部分 php 配置
PHP_ADMIN_VALUE
设置auto_prepend_file = php://input且allow_url_include = On,然后将我们需要执行的代码放在Body中,即可执行任意代码。
{
'GATEWAY_INTERFACE': 'FastCGI/1.0',
'REQUEST_METHOD': 'GET',
'SCRIPT_FILENAME': '/var/www/html/index.php',
'SCRIPT_NAME': '/index.php',
'QUERY_STRING': '?a=1&b=2',
'REQUEST_URI': '/index.php?a=1&b=2',
'DOCUMENT_ROOT': '/var/www/html',
'SERVER_SOFTWARE': 'php/fcgiclient',
'REMOTE_ADDR': '127.0.0.1',
'REMOTE_PORT': '12345',
'SERVER_ADDR': '127.0.0.1',
'SERVER_PORT': '80',
'SERVER_NAME': "localhost",
'SERVER_PROTOCOL': 'HTTP/1.1'
'PHP_VALUE': 'auto_prepend_file = php://input',
'PHP_ADMIN_VALUE': 'allow_url_include = On'
}
以上介绍的只是对PHP-FPM进行攻击的正常流程,假如环境中增加了disable_functions的限制,如果使用包含PHP_VALUE==disable_function=的恶意FastCgi攻击FPM时,只能修改展示phpinfo信息的EG(ini_directives),也就是表面修改,对于已经禁用的函数无效的。
0X02 实例解析
以SUCTF2019中的一道题为例easyphp,在获得webshell以后,发现有disable_functions的限制,这里可以通过与php-fpm进行通信来绕过open_basedir。
这里想要获得flag需要利用php_value对open_basedir的值进行重设
'PHP_VALUE': 'auto_prepend_file = php://input'+chr(0x0A)+'open_basedir = /',
官方给的环境很有问题,少了upload目录,需要自行加上,进去以后直接用官方给的exp复现也没成功,进去docker发现php-fpm根本没有起,emmmm醉了
直接在ubuntu16.04起一个phpfpm
sudo apt update sudo apt install -y nginx sudo apt install -y software-properties-common sudo add-apt-repository -y ppa:ondrej/php sudo apt update sudo apt install -y php7.3-fpm
修改nginx站点文件
sudo vim /etc/nginx/sites-enabled/default
启用unix socket模式
sudo vim /etc/php/7.3/fpm/pool.d/www.conf
配置php-fpm监听,将listen参数修改为127.0.0.1:9000
重启php-fpm和nginx
/etc/init.d/php7.3-fpm restart
service nginx restart
修改相应的open_basedir
利用php-fpm通信来修改basedir,用p神的脚本修改一下
最后绕过open_basedir成功
0X03 参考链接
留言或私信获取链接哦
前言
nginx转发php类型的请求可以通过fastcgi的方式,fastcgi支持TCP和 unix domain socket两种方式。
Unix domain socket监听
Unix domain socket 或者 IPC socket是一种终端,可以使同一台操作系统上的两个或多个进程进行数据通信。
与管道相比,Unix domain sockets 既可以使用字节流和数据队列,而管道通信则只能通过字节流。
Unix domain sockets的接口和Internet socket很像,但它不使用网络底层协议来通信。Unix domain socket 的功能是POSIX操作系统里的一种组件。
TCP监听
通过网络TCP链接建立网络通信,即使是监听127.0.0.1,也是通过网络底层协议来通信。相对于socket方式,会消耗一些网络资源。
选择TCP还是Unix domain socket?
如果nginx和php-fpm都在同一台机器,当然是选择Unix domain socket方式;但是如果nginx和php-fpm不在同一台机器,socket方式就不能用了。
如果网站的静态资源和php处理的页面是分开的,需要较高的处理能力,可以选择将nginx和php-fpm分开,通过TCP监听的方式组成集群进行处理。(因为fastcgi么有转发静态资源,所以需要nginx将静态资源转发对应的静态资源的目录)
php配置
php-fpm 修改 php-fpm.conf
TCP模式:
listen = 0.0.0.0:9000
Unix domain socket模式:
listen = /opt/php/var/run/php-fpm.sock ; 这里的目录也可以选择/dev/shm/php-fpm.sock,/dev/shm/是一个内存的目录,相对读写的速度会快一点。
nginx修改
TCP模式:
upstream fpm_server{server 192.168.122.100:9000; server 192.168.122.101:9000;}server { listen 80; server_name localhost; root /var/www/php; location ~ [^/]\.php(/|$) { fastcgi_pass fpm_server; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi.conf; }}
Unix domain socket模式:
server {listen 80; server_name localhost; root /var/www/php; location ~ [^/]\.php(/|$) { fastcgi_pass unix:/opt/php/var/run/php-fpm.sock; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi.conf; }}
总结
在服务器压力不大的情况下,tcp和Unix domain socket差别不大,但在压力比较满的时候,用套接字方式,效果比较好。
服务提供注册方法:
register() //所有提供者提供服务之前提供boot() //所有提供者提供服务之后提供延迟服务提供配置:
protected $defer = true;
服务提供位置:
配置文件:config/app.php providers=>[]框架中固定写好的:eg:注册服务 registerBaseServiceProviders() //position: vendor/laravel/framework/src/Illuminate/Foundation/Application.php门脸模式为容器中可用的类提供一种静态的调用方法 eg:\Request::all()
位置:config/app.php
aliases=>[ 'Request' => Illuminate\Support\Facades\Request::class,
]
其实,所有的门脸类中只有一个方法,即返回对应的IOC控制反转中的标签
namespace Illuminate\Support\Facades;
/**
* @see \Illuminate\Http\Request
*/
class Request extends Facade
{
/**
* Get the registered name of the component.
*
* @return string
*/
protected static function getFacadeAccessor()
{
return 'request';
}
}
示例分析日志类
查看日志:
tail -f storage/logs/laravel.log
1.容器vendor/laravel/framework/src/Illuminate/Foundation/Application.php 中找到 registerBaseServiceProviders()方法,追踪到下面方法register(),可看出绑定到 log 字符串
public function register(){$this->app->singleton('log', function () { return $this->createLogger(); });}code:
$app = app(); //获取容器
$log = $app->make('log'); //从容器中获取日志类,并解析(找到绑定的过程确定容器中字符串) $log->info("post_index",['data'=>'hello log!']);
.依赖注入
服务注册名字叫log可在当前文件找出设置的别名,其对应的三个别名都相当于获取log,position:vendor/laravel/framework/src/Illuminate/Foundation/Application.php,
'log' => [\Illuminate\Log\Writer::class, \Illuminate\Contracts\Logging\Log::class, \Psr\Log\LoggerInterface::class],
3.门脸模式
通过 config/app.php 设置 aliases 别名
'Request' => Illuminate\Support\Facades\Request::class,
code:
public function index(){
\Log::info('post_info',['data'=>'hello menlian!']);
}
一. PHP设计与管理的重要性
从PHP诞生到被更多的应用到项目中,已经过去了很多年。在这中间一批一批的后继者为PHP的发展,不断地探索。当然,你或许也很好奇PHP,因为太易于使用,并在短时间内能给出令你满意的结果。
你可能会将大量代码直接写在Web页面上,你也可能在文件中使用工具函数,再去执行它,都是ok的,PHP允许你这样做。但是你已经走上一条毁灭之路,并且陶醉其中。当然一开始的你不会那么迅速的意识到这个严重的问题,因为你的站点看起来如此美妙,并且客户也喜欢,愿意为之付费。
当你的项目到达一个新的阶段时,团队更大、客户更多、资金更多。这时事态开始恶化,你的项目就像中了毒一样。
新加入的程序员开始理解你的代码,他今天的任务可能只需要实例化a类,但是由于你一开始的挖的坑,他花费一整天的时间都可能没完成工作。
这时意识到这个严峻的问题,你尝试去改变,可是发现一个微小的改动,牵扯到20多个文件,预计1天的时间,最终竟然超过3天。
你的站点这时非常受欢迎了,需要迁移到新的服务器,可是你发现诸多文件路径、数据库等信息全被硬编码到许多文件中。或许有人自作聪明修改apache的URL重写模块。这些都将导致你无法再预计时间内完成项目。
前一天晚上修改代码由于疏忽,导致一整晚购物车无法运行。在你酣睡期间,顾客并没有睡觉。自然第二天既要解决代码问题,又要安抚顾客,并且集合队伍开始另一场救火行动...
上面的故事你可能觉得有点夸张,但是我看到现实中这些事一而再再而三的发生。许多PHP的项目都是从一个小项目变成令人恐惧的怪兽。
当然,如果你是一个PHP技术顾问,上面的问题并非坏消息。评估和修复一个这样的系统足够你未来半年或更长时间嘿嘿嘿了。但严肃看待,此类问题通常意味着一个业务的成功或失败。
我们的目标是实现构建实现既定目标的系统,并且他们易于进行协作开发。作为程序员我们创造了拥有“形状”和“行为”的机器,我们一生投入了很多天,每天也投入了很多个小时来开发程序,使这些机器的“形状”诞生。我们希望我们创造的单个类或对象、软件组件直至最终产品,能够构成一个优雅整体。
二. 面向对象、设计模式
面向对象并非PHP唯一的工作方法,但是它被认为是开发企业级系统的强大助力和重要方法,并且未来它将持续发光发热,我们很自然的选择它来解决我们遇到的麻烦。
如果PHP的面向对象你不了解,可以私聊我或在网上寻找资料。
熟悉面向对象的同学,应该熟知一个内容【涉及模式】。在开发过程中,我们所遇到的大部分问题其实都已被其他程序员一再的处理了。设计模式意味着智慧。一个模式一旦成为通用模式,就能丰富我们的语言,使我们可轻松的分享设计思想及这些思想所带来的成果。设计模式提取了共同问题,定义了经过测试的解决方案并描述了可能的结果。它更关注如何才能从这些语言基础中继续深入,继而理解项目中出现的问题及找出相应的潜在解决方案。
一个设计模式的核心由4部分组成:命名、问题、解决方案和效果。
《设计模式》一书中曾写道“找到一个好名字,成了我们在开发模式目录中最困难的部分之一”,简短明确的文字,可以表示相当复杂的问题和解决方案。
问题是模式的基础,我们的模式将是小心谨慎的描述问题空间。
解决方案最初是和问题放在一起的。模式通常包含一个返利代码。
通过简单的了解,我们了解到设计模式可以简单的描述问题的解决方案,但是我们同样重视解决方案的可重用性和灵活性。我们下节将具体阐述:
组合:如何通过聚合对象来获的比只使用集成更好的灵活性
解耦:如何降低系统中元素间的依赖性
接口的作用:模式和多态
模式分类等
ThinkPHP是一款开源框架,在web应用中占有很大地位。但是很多新手在加载及使用分组模式时由于目录较多,可能不知道如何配置。在此分享个人经验,以助新人快速掌握分组模式的配置
在web根目录下新建project文件夹
将下载好的ThinkPHP放入project目录下,并在project目录下新建Public文件夹、blog文件夹(名字最好是项目名称)、index.php
在index.php中写下如图代码。
加载成功后打开index.php回出现如图笑脸
在blog文件夹下新建Modules文件夹,再在Modules文件夹下新建Home和Admin文件夹
在Home和Admin文件夹下分别新建如图所示四个文件夹
修改blog/Conf下的配置文件config.php,如下
至此大功告成,你可以编写模块了
各位朋友大家好!
今天给大家带来的是 php基础里面的工厂设计模式!
在面向对象编程中, 最通常的方法是一个new操作符产生一个对象实例,new操作符就是用来构造对象实例的。但是在一些情况下, new操作符直接生成对象会带来一些问题。举例来说, 许多类型对象的创造需要一系列的步骤: 你可能需要计算或取得对象的初始设置; 选择生成哪个子对象实例; 或在生成你需要的对象之前必须先生成一些辅助功能的对象。 在这些情况,新对象的建立就是一个 “过程”,不仅是一个操作,像一部大机器中的一个齿轮传动。
这里那就需要运用到一个 工厂设计模式的PHP类!
由于源码比较长,需要的朋友可以私聊小编哦
废话不多说,上源码!
<?php
//人类接口
interface IHuman
{
function GetName();
}
//男人类,实现人类接口
class ManClass implements IHuman
{
//获取姓名方法
public function GetName()
{
return "I'm man."."<br>";
}
}
//女人类,实现人类接口
class WomanClass implements IHuman
{
//获取姓名方法
public function GetName()
{
return "I'm Woman."."<br>";
}
}
//类工厂,根据需要生产不同实例对象返回
class ManFactory
{
//根据参数获取实例对象
public function GetIHuman($IHuman="man")
{
if($IHuman=="woman")
{
return new WomanClass();
}
else if($IHuman=="man")
{
return new ManClass();
}
else
{
return null;
}
}
//直接获取woman类
public function GetWoman()
{
return new WomanClass();
//return new ManClass();
}
//直接获取man类
public function GetMan()
{
return new ManClass();
}
}
$ManFactory=new ManFactory();
$ManClass=$ManFactory->GetIHuman();
echo $ManClass->GetName();
$IHuman=$ManFactory->GetIHuman("woman");
echo $IHuman->GetName();
$Woman=$ManFactory->GetWoman();
echo $Woman->GetName();
$Man=$ManFactory->GetMan();
echo $Man->GetName();
?>
本篇文章主要给大家介绍PHP设计模式中的代理模式。首先大家需要对PHP设计模式这个概念有一定的了解。
所谓的PHP设计模式,在我们日常项目开发中是会经常被使用到的,并且通常会体现在框架中,表现出一种特定的编码技巧。PHP中的设计模式可以提取一些共同的问题,定义一些经过测试的解决方案,同时描述可能的结果。
简单的说,设计模式(Patterns)是一些可以在项目中重复使用的解决方案。
那么PHP代理模式就是PHP设计模式之一。
代理模式(Proxy Pattern) ,顾名思义,重点就是代理。也就是表示,给某一个对象提供一个代理,并由代理对象控制对原对象的引用。
代理模式的英文叫做Proxy或Surrogate,它是一种对象结构型模式。
这种模式是在客户端和真实主体(RealSubject)之间插入一个代理对象,维护subject接口和用不同的方式委派它的方法。
或者也可以这样理解,代理模式可以提供与代购网站类似的功能。所谓代购,大家肯定都比较清楚。常见的,比如让专门做代购的商家从国外帮你代购一些特定的商品(国内买不到或者价格非常昂贵)。
像这种因为一些特殊原因,客户端不想或不能直接访问一个对象,这时可以通过一个称之为“代理”的第三者来实现间接访问,该方案对应的设计模式也就叫做
代理模式
。
如上图中代理模式关系图:Subject表示抽象主题角色,Proxy表示代理主题角色,RealSubject表示真实主题角色。
php实现代理模式的方法
本篇文章就是关于PHP代理模式的基本介绍,也是比较简单易懂,希望对需要的朋友有所帮助!