大家好!我们写的代码想要运行起来就必须要有环境,没有执行环境代码是运行不起来的,那么如何搭建一个最简单环境呢?搭建环境有两种方式:一:linux系统环境下面编译安装。二:win系统一键安装包。为了让新手能快速入门,我这里只讲Windows系统(win7/win8/win10)环境下一键安装包的搭建方式,毕竟新手对Windows操作很熟悉。
一:PHP一键安装包的方式。
所谓一键安装包就是把apache+mysql+php全部集成安装好,简单省心。到现在很多中级程序员,甚至少数高级程序员都是用一键安装包搭建自己的运行环境。
下载一键安装包。我推荐去phpstudy的官网上面下载选择Windows版本的。
下载phpstudy一键安装包下载之后,点击exe结尾的执行文件。记得不要用用默认安装,默认的话会安装在C盘里面。所有下载安装的软件尽量不要安装在C盘,这个是常识。要选择自定义安装在D盘或者E盘里面。
2:如何启动一键安装包。
点击启动apache按钮apache启动之后的界面安装完成后,点击apache的启动按钮,php运行环境搭建好了。暂时mysql可以不启动,mysql是存放数据用的。后面再教大家如何使用mysql。
2:配置虚拟域名。
由于工作实际开发过程中都是用域名来访问,比如后面用的Laravel框架,thinkphp框架都是配置域名来访问的,所以我们就配置一个域名来访问服务器。
配置虚拟域名在phpsudy控制面板里面,选择最下面的【设置】-》hossts,用记事本打开输入127.0.0.1 test100.com。这个网址(域名)是随便取的,可以根据自己的爱好修改,记得保存。意思就是我在浏览器访问test100.com这个网站,实际上是访问自己本电脑的apache服务器。顺便补充一下上图IP地址前面的#号是失效的意思,和删除是一个道理,所以正常使用的前面就不要加#号了。
3:配置虚拟域名的艮目录。
配置网站域名的根目录继续选择最下面的【网站】-》【新建网站】-》【基本配置】域名一栏,填写刚才自己的域名,比如test100.com。根目录的路径写到安装phpstudy的www目录下面,点击保存。
4:测试php运行环境。
访问搭建的php运行环境在浏览器里面输入刚才的网址(域名),提示站点创建成功。ok大功告成,估计不会写代码的人也会搭建了,以后就可以建设自己的网站了。记得www是根目录,php代码都要放在这个目录(文件夹)里面,放在别的地方就运行不了。有疑问的请给我留言,乐于效劳。
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 参考链接
留言或私信获取链接哦
什么是百度熊掌号?百度熊掌号是内容和服务提供者入驻百度生态的实名账号,致力于帮助内容和服务提供者方便、快捷、高效地连接百度用户,并充分利用搜索生态开放的优势,获得流量和沉淀用户,实现自身价值的快速增长。加入熊掌号后,搜索结果会根据熊掌号进行排序;搜索会有检索、排序的优待;在流量转化上,熊掌号可以将用户搜索需求的结果,连接到相应的服务提供商,实现流量转化;在品牌曝光方面,将生产方在全网生产的内容都连接到熊掌号上;在用户运营方面,增加内容和服务提供者的双向连接
那么百度熊掌号如何申请开通?
登录百度熊掌号平台,申请熊掌号注册;已有百家号的用户可使用账号直接进入第二步;完成熊掌号注册后,进入熊掌号平台-搜索资源平台,申请数据提交资格;通过审核后,收到搜索资源平台发送的短信和邮件,回到搜索资源平台,按照界面中的提示完成落地页体验和技术改造;通过搜索资源平台数据提交接口完成熊掌号新增/历史数据的提交。
好了,让我们进入正题吧!百度熊掌号,里面有一个功能,就是资源提交!如下图:
它分有:API提交和手动提交,比较人性化,可以满足不同需求的站长。
当然,本文是介绍如何在thinkphp5.1框架下开发API,让网站的资源进行自动提交。
thinkphp5.1如何实现熊掌号资源API提交功能?
本thinkphp5.1实例说明:由于推送是实施推送的,所以我把API接口直接写在了文章更新的控制器里面,作为一个API接口方法,提供给文章添加的方法里,每增加一条内容,就自动推送地址到百度熊掌号里。
第一步,让我们看看百度熊掌号里的API的PHP推送示例代码
$urls = array( 'http://www.example.com/1.html', 'http://www.example.com/2.html',);$api = 'http://data.zz.baidu.com/urls?appid=XXXX&token=XXXXX&type=realtime';$ch = curl_init();$options = array( CURLOPT_URL => $api, CURLOPT_POST => true, CURLOPT_RETURNTRANSFER => true, CURLOPT_POSTFIELDS => implode("\n", $urls), CURLOPT_HTTPHEADER => array('Content-Type: text/plain'),);curl_setopt_array($ch, $options);$result = curl_exec($ch);echo $result;
第二步,打开文章管理的控制器,然后创建百度熊掌号API方法
注意:我是往方法里传递了一个文章ID参数。
第三步,在文章管理的控制器,文章增加的方法上进行调用
在这里,文章增加方法里的添加数据方式有两种情况,第一种,直接通过助手函数DB进行添加,第二种是通过模型进行数据处理的。
第一种:
$add = db('content')->insertGetId($data);if ($add){ $this->BaiDuTui($add);}
第二种:
$res = $this->db->store($data);if ($res){ $getId = $this->db->art_id; $this->BaiDuXiongApi($getId); $this->BaiDuTuiApi($getId);}
具体的thinkphp5.1函数介绍,请参阅手册,或者留言给我。
但本篇文章发布后,百度熊掌号资源提交哪里就会发生变化,数量随之减一,补图:
本篇文章主要给大家介绍实现一个PHP类来计算整数的阶乘。首先大家简单了解一下什么是阶乘?
一个正整数的阶乘(factorial)是所有小于及等于该数的正整数的积,并且0的阶乘为1。自然数n的阶乘写作n!。
简单的说,比如6的阶乘就是6!=1*2*3*4*5*6
那么我们如何实现PHP类来计算整数的阶乘?
实现代码如下:
<?php
class factorial_of_a_number
{
protected $_n;
public function __construct($n)
{
if (!is_int($n))
{
throw new InvalidArgumentException('Not a number or missing argument');
}
$this->_n = $n;
}
public function result()
{
$factorial = 1;
for ($i = 1; $i <= $this->_n; $i++)
{
$factorial *= $i;
}
return $factorial;
}
}
$newfactorial = New factorial_of_a_number(5);
echo $newfactorial->result();
?>
相关函数介绍:上述代码就是计算出5的阶乘,输出结果为120。
is_int()函数检测变量是否是整数。
__construct() 函数创建一个新的 SimpleXMLElement 对象。PHP 5 允行开发者在一个类中定义一个方法作为构造函数。具有构造函数的类会在每次创建新对象时先调用此方法,所以非常适合在使用对象之前做一些初始化工作。
我们可以用一个逻辑图来表示:
本篇文章就关于实现一个PHP类计算整数阶乘的方法介绍,具有一定的参考价值,希望对需要的朋友有所帮助!
PHP递归函数求阶乘方法
尽量完整的需求方案,具体到功能上:建模结构UML,建立数据库: 1、建立的表名、字段名要与他的功能有关系。 2、根据结构建立数据库表,原则是不定项内容一定要分表。 3、字段类型要考虑内容是否够用就够就好,选择适合的类型INT Varchar Date(4)设计HTML文件和脚本的实现 根据模和数据库来设计页面是个很科学的方法,当然有的时候有人喜欢根据模型设计页面,数据库基于页面设计,都是可以的。 设计页面时要考虑到每个细节,包括提示消息页面,错误页面。(5)PHP代码的书写1、先建立底层结构和文件夹(如果是大型的网站同样设计一个文件UMML)2、基础功能分类关联,以便今后代码引用。3、代码的书写,注意简洁性和函数的使用,内部函数能实现的尽量使用内部函数。4、在部分关键位置加以代码注释。(6)程序的测试和修正1、对于发现的BUG不能就解决BUG而解决,要处于完整程序考虑。避免收之东隅收之桑榆。2、对于解决过的BUG已经要详细记录,以便日后更新。多人开发应该注意什么使用版本服务器:CVS、SVN...功能:1、单个文件历史版本的记录和恢复2、文件的锁定和更新3、单个或多个文件程序之间的沟通4、保护程序的安全性不受单个程序的误操作而丢失
尽量完整的需求方案,具体到功能上:建模结构UML,建立数据库: 1、建立的表名、字段名要与他的功能有关系。 2、根据结构建立数据库表,原则是不定项内容一定要分表。 3、字段类型要考虑内容是否够用就够就好,选择适合的类型INT Varchar Date(4)设计HTML文件和脚本的实现 根据模和数据库来设计页面是个很科学的方法,当然有的时候有人喜欢根据模型设计页面,数据库基于页面设计,都是可以的。 设计页面时要考虑到每个细节,包括提示消息页面,错误页面。
(5)PHP代码的书写1、先建立底层结构和文件夹(如果是大型的网站同样设计一个文件UMML)2、基础功能分类关联,以便今后代码引用。3、代码的书写,注意简洁性和函数的使用,内部函数能实现的尽量使用内部函数。4、在部分关键位置加以代码注释。(6)程序的测试和修正1、对于发现的BUG不能就解决BUG而解决,要处于完整程序考虑。避免收之东隅收之桑榆。2、对于解决过的BUG已经要详细记录,以便日后更新。多人开发应该注意什么使用版本服务器:CVS、SVN...功能:1、单个文件历史版本的记录和恢复2、文件的锁定和更新3、单个或多个文件程序之间的沟通4、保护程序的安全性不受单个程序的误操作而丢失
文章来源:昆明网站建设专业品牌——找北网络科技(zhaobeikj.com)
本文实例讲述了PHP扩展Swoole实现实时异步任务队列。分享给大家供大家参考,具体如下:
假如要发100封邮件,for循环100遍,用户直接揭竿而起,什么破网站!
但实际上,我们很可能有超过1万的邮件。怎么处理这个延迟的问题?
答案就是用异步。把“发邮件”这个操作封装,然后后台异步地执行1万遍。这样的话,用户提交网页后,他所等待的时间只是“把发邮件任务请求推送进队列里”的时间。而我们的后台服务将在用户看不见的地方跑。
在实现“异步队列”这点上,有人采用MySQL表或者redis来存放待发送的邮件,然后,每分钟定时读取待发送列表,然后处理。这便是定时异步任务队列。但当前提交的任务要一分钟后才能执行,在某些实时性要求应用场景里还是不快。有些场景要求,只有一提交任务,便马上执行,但用户不需要等待返回结果。
本文将探讨用php扩展swoole实现实时异步任务队列的方案。
服务端
在打算放置脚本的目录(你也可以自行新建)新建Server.php,代码如下
启动服务后,让我们看看如何调用服务。新建测试文件Client_test.php客户端
保存好代码,在命令行或者浏览器中执行Client_test.php,便实现了异步任务队列。你所填写的URL,将会在每次异步任务被提交后,以HTTP GET的方式异步执行。在上面代码中,url即为任务所在地址,param为所需传递参数。
选择排序在冒泡排序的基础上进行了改进,每次通过列表时只进行一次传递交换。简单来说,选择排序的原理就是每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,直到全部待排序的数据元素排完。 选择排序是不稳定的排序方法。
PHP选择排序的代码示例如下:
<?phpfunction selection_sort($data){for($i=0; $i<count($data)-1; $i++) { $min = $i; for($j=$i+1; $j<count($data); $j++) { if ($data[$j]<$data[$min]) { $min = $j; } } $data = swap_positions($data, $i, $min); } return $data;}function swap_positions($data1, $left, $right) { $backup_old_data_right_value = $data1[$right]; $data1[$right] = $data1[$left]; $data1[$left] = $backup_old_data_right_value; return $data1;}$my_array = array(3, 0, 2, 5, -1, 4, 1);echo "原始数组:\n";echo implode(', ',$my_array );echo "\n排序后数组:\n";echo implode(', ',selection_sort($my_array)). PHP_EOL;
输出:
原始数组:3, 0, 2, 5, -1, 4, 1 排序后数组:-1, 0, 1, 2, 3, 4, 5
本篇文章就是关于PHP选择排序的实现方法介绍,希望对需要的朋友有所帮助!
本文将讲解如下内容:
PHP原生进程函数介绍PHP实现多进程代码
01PHP原生进程函数
虽然说PHP是世界上最好的语言,但是对于PHPer们来说,对多进程、进程管理还是相对陌生的。本文将讲解一下使用PHP原生代码如何实现多进程。
首先我们要了解PHP实现多进程的函数,如pcntl_fork、pcntl_wait、pcntl_waitpid等。
pcntl_fork ( void ) : int
这个函数的作用是创建子进程,并且返回 int 类型的进程ID,父进程和子进程都是从fork的位置开始向下继续执行。
子进程创建成功时,在父进程执行线程内返回产生的子进程的PID,在子进程执行线程内返回0。创建失败时,在父进程上下文返回-1,不会创建子进程,并且会引发一个PHP错误。
pcntl_wait ( int &$status [, int $options = 0 ] ) : int
这个函数的作用是等待或返回fork的子进程状态。此函数会挂起当前进程的执行,直到一个子进程退出或者受到一个信号要求中断当前进程或者调用一个信号处理函数。如果一个子进程在调用此函数时已经退出,此函数立刻返回。
此函数返回退出的子进程号,发生错误时返回-1,如果提供了WNOHANG作为option并且没有可用子进程时返回0。
pcntl_waitpid ( int $pid , int &$status [, int $options = 0 ] ) : int
这个函数的作用是等待或返回fork的子进程状态。调用这个函数会挂起当前进程的执行,直到参数pid指定的进程号的进程退出,或者接收到一个信号要求中断当前进程或调用一个信号处理函数。
pcntl_waitpid()返回退出的子进程进程号,发生错误时返回-1,如果提供了 WNOHANG作为option,并且没有可用子进程时返回0。
pcntl_signal ( int $signo , callback $handler [, bool $restart_syscalls = true ] ) : bool
这个函数的作用是安装信号处理器,为signo指定的信号安装一个新的信号处理器。
signo为信号编号。
handler为信号处理器,可以是用户创建的函数或方法,也可以是系统常亮SIG_IGN(忽略信号处理程序)或 SIG_DFL(默认信号处理程序)。
restart_syscalls 指定当信号到达时系统调用重启是否可用。
函数返回值为bool型,成功时返回true,失败时返回false。
02PHP实现多进程代码
如有疑问,可以留言相互讨论。
由于工作需要将一个在linux端运行的软件可视化,打算基于web的形式将其可视化。带来的问题是如何跨平台无缝衔接web和linux中的软件,有幸的看到一个方法,利用ssh2技术即可实现我的需求。下面提供我的案例:
首先在linux端安装ssh2包,然后在需要执行linux命令,运行linux端程序的页面加入以下代码:
$host='*******';//服务器的ip$user='****';//用户名$passwd='******';//密码// 链接远程服务器$connection = ssh2_connect($host, 22); if (!$connection) die('connection to '.$host.':22 failed'); echo'connection OK'; // 获取验证方式并打印$auth_methods = ssh2_auth_none($connection, $user); print_r( $auth_methods.''); if (in_array('password', $auth_methods )) { // 通过password方式登录远程服务器if (ssh2_auth_password($connection, $user, $passwd)) { echo$user.' login OK'; $stream = ssh2_exec($connection, "命令1&&命令2"); // 一条一条地执行linux命令stream_set_blocking($stream, true); // 获取执行pwd后的内容if ($stream === FALSE) die("pwd failed"); echo stream_get_contents($stream).''; } else{ die( $user.' login Failed'); } } ?>
亲测有效。
用文件的方式读写,一个文件是索引文件,另一个文件是真实的数据文件。
索引文件分为2部分,第一部分是所有的指针,记录第二部分的位置;第二部分是索引记录。所有的索引指针:是记录所有相同Hash值的key的指针,它是一个链表结构,记录在数据文件的位置和同key的下一个值。
索引记录中:每条记录有四部分,第一部分4个字节,是下一条索引的偏移量;第二部分是该记录的key,128字节;第三部分是数据偏移量,4个字节;第四部分是数据记录长度,4个字节。
我们设定文件的存储上限为262144个。
查找流程如下:
1、根据key算出hash值,获取该hash值的链表在索引文件的第一部分(所有指针区)的位置。
2、根据步骤一的位置,获取值,时间复杂度O(1);
3、根据步骤一中的值,找到索引文件中第二部分(索引记录)的位置,也就是和key相同hash值的所有指针的链表。顺着链表查找该key,获取该key在链表中存放的数据,数据只包含该key在索引文件中的位置,时间复杂度为O(n);
4、根据步骤二所获取的key在索引文件位置,得到索引文件中存放该key的信息。信息包含在真实数据文件中存放真实数据的位置。
5、根据步骤三所获取的位置,在真实数据文件中获取数据,并返回给应用程序。
测试结果:插入10000条耗时:793ms。查找10000条耗时:149ms。虽然这效率只有Redis的十分之一。。。但是请不要在意这些细节。
代码做了注释,上述文字有些乱。代码只实现三个方法,一个插入(如果存在则跳过),一个是查找,一个是删除。