最实用有效的PHP中防止SQL注入
问题描述:
如果用户输入的数据在未经处理的情况下插入到一条SQL查询语句,那么应用将很可能遭受到SQL注入攻击,正如下面的例子:
代码如下 | 复制代码 |
$unsafe_variable = $_POST['user_input']; mysql_query("INSERT INTO `table` (`column`) VALUES ('" . $unsafe_variable . "')"); |
因为用户的输入可能是这样的:
代码如下 | 复制代码 |
value'); DROP TABLE table;-- |
那么SQL查询将变成如下:
代码如下 | 复制代码 |
INSERT INTO `table` (`column`) VALUES('value'); DROP TABLE table;--') |
应该采取哪些有效的方法来防止SQL注入?
最佳回答(来自Theo):
使用预处理语句和参数化查询。预处理语句和参数分别发送到数据库服务器进行解析,参数将会被当作普通字符处理。这种方式使得攻击者无法注入恶意的SQL。 你有两种选择来实现该方法:
1、使用PDO:
代码如下 | 复制代码 |
$stmt = $pdo->prepare('SELECT * FROM employees WHERE name = :name'); $stmt->execute(array('name' => $name)); foreach ($stmt as $row) { // do something with $row } |
2、使用mysqli:
代码如下 | 复制代码 |
$stmt = $dbConnection->prepare('SELECT * FROM employees WHERE name = ?'); $stmt->bind_param('s', $name); $stmt->execute(); $result = $stmt->get_result(); while ($row = $result->fetch_assoc()) { // do something with $row } |
PDO
注意,在默认情况使用PDO并没有让MySQL数据库执行真正的预处理语句(原因见下文)。为了解决这个问题,你应该禁止PDO模拟预处理语句。一个正确使用PDO创建数据库连接的例子如下:
$dbConnection = new PDO('mysql:dbname=dbtest;host=127.0.0.1;charset=utf8', 'user', 'pass');
$dbConnection->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$dbConnection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
在上面的例子中,报错模式(ATTR_ERRMODE)并不是必须的,但建议加上它。这样,当发生致命错误(Fatal Error)时,脚本就不会停止运行,而是给了程序员一个捕获PDOExceptions的机会,以便对错误进行妥善处理。 然而,第一个setAttribute()调用是必须的,它禁止PDO模拟预处理语句,而使用真正的预处理语句,即有MySQL执行预处理语句。这能确保语句和参数在发送给MySQL之前没有被PHP处理过,这将使得攻击者无法注入恶意SQL。了解原因,可参考这篇博文:PDO防注入原理分析以及使用PDO的注意事项。 注意在老版本的PHP(<5.3.6),你无法通过在PDO的构造器的DSN上设置字符集,参考:silently ignored the charset parameter。
解析
当你将SQL语句发送给数据库服务器进行预处理和解析时发生了什么?通过指定占位符(一个?或者一个上面例子中命名的 :name),告诉数据库引擎你想在哪里进行过滤。当你调用execute的时候,预处理语句将会与你指定的参数值结合。 关键点就在这里:参数的值是和经过解析的SQL语句结合到一起,而不是SQL字符串。SQL注入是通过触发脚本在构造SQL语句时包含恶意的字符串。所以,通过将SQL语句和参数分开,你防止了SQL注入的风险。任何你发送的参数的值都将被当作普通字符串,而不会被数据库服务器解析。回到上面的例子,如果$name变量的值为 ’Sarah’; DELETE FROM employees ,那么实际的查询将是在 employees 中查找 name 字段值为 ’Sarah’; DELETE FROM employees 的记录。 另一个使用预处理语句的好处是:如果你在同一次数据库连接会话中执行同样的语句许多次,它将只被解析一次,这可以提升一点执行速度。 如果你想问插入该如何做,请看下面这个例子(使用PDO):
代码如下 | 复制代码 |
$preparedStatement = $db->prepare('INSERT INTO table (column) VALUES (:column)'); $preparedStatement->execute(array('column' => $unsafeValue)); |
Drupal 配置迁移是什么?很多 Drupaller 对这个话题感到无所适从,新人工作之初并不会意识到这个问题的存在,而意识到这个问题的朋友也不确定怎样正确地进行配置迁移。本文就围绕 Drupal 配置迁移的原因、方式/方法及相关模块较为系统地聊聊这个话题。
如果你被以下问题困扰,仔细阅读本文将会对你有所助益
修改了一些站点配置(如站点名称、标语或任何存在于variables表中的变量值),怎么一次性部署到线上?怎么跟踪每次的修改记录?(大部分情况下你是不是直接在线上修改了:D)
在开发环境中页面布局进行了调整,修改了区块的配置(如位置、显示条件)和内容,怎么样才能快速地部署到线上(是不是手动一个一个去调整,把做过的事情重新再做一遍——这样很无趣,也很费时,还容易遗漏和出错,尤其是当这些配置之前是由其它人配置的,想要再准确地复现将会非常困难)
在开发环境中添加了几个新的字段、内容类型、输入格式、Wysiwyg配置或者视图,不想在线上再手动操作,点鼠标点到手发麻,又应该怎么办?
开发过程中需要大量实际数据,不能直接在线上操作,如何把实际数据从线上迁移到开发环境中?
……
为什么 Drupal 要做配置迁移?
大家都熟悉传统的Web开发,主要工作都是面对代码,不管是PHP、CSS、HTML或JS,几乎所有的工作都是在文件中完成。如果要更新或升级某些功能,做好备份后上传修改过的文件就能完成,So Easy!
对Drupal而言,配置迁移就不那么简单了,因为文件迁移只是 Drupal 配置迁移的一小部分,Drupal 中大部分的配置存在于数据库中。而因为线上环境的数据库时刻在变化,要把开发环境中一部分数据库的内容更新到线上而又不影响线上的内容,可不是一件容易的事。
Drupal将配置存在于数据库中是经常被Drupal老手们诟病的问题之一——最大的缺点是你不能简单地迁移数据库中的某些值或对其实行版本控制,当然这样设计的优点在于方便开发人员进行研发,以及方便使用者通过界面(而不需要修改代码)非常快速地对功能进行调配。(再一次,Drupal选择了灵活性而牺牲了其它东西)
在D8之前,Drupal没有统一的标准来规范大家应该如何存储各自己的配置数据,不同模块的配置格式和存储方式并不相同,因此也就无法通过某种特定的方式一次性迁移出所有配置数据。
(D8开始实施配置管理系统了,从此对配置的管理有了统一的规范和标准,可参见《Drupal 8 配置管理机制及新特性简介》)
而另外一点造成Drupal的配置迁移成为一个难点话题的原因在于,D8之前,Drupal的配置和内容混合存储在数据库中,很难将两者分离开,如果只是通过覆盖数据库的方式来进行操作,无法做到只改变配置而不触及内容,反之亦然。
因为设计上的原因,使得Drupal的配置迁移成了一个难点,针对于它的工作流程和解决方案也就成了一个独立的、不可回避的且颇有意思的话题。
目前有关Drupal配置迁移的处理方式已经非常成熟,D8之前的配置迁移可以参考本文,D8的配置迁移大家去学习其配置管理系统的知识并熟练运用即可。虽然D8之前没有官方统一的标准配置管理体系,但D8配置管理体系的很多理念与本文提及的各种配置迁移方式是相同的,因此学习本文也将会使之后了解D8的配置管理系统变得更为容易一些。
加强 Drupal 配置迁移自动化的优点
相信有很多朋友在做 Drupal 开发时会先在本地做一次,然后到测试环境或生产环境再做一次。当然这也不失为一种方式,对小站点的功能部署还能适用,但对于在线下进行了几周甚至几个月的工作量,再重复做一次的代价可是相当大的——前提还要是每个人都记得整段时间都按什么顺序做了什么配置。
如果大家希望更轻松、更准确、更高效、更简单地完成配置迁移的任务,不妨学会如何让配置迁移更为自行化。
以下是通过各种工具进行自动化配置迁移的一些主要优点:
减轻工作量——大量配置的部署真的可以点鼠标点到手发麻,将大量点击操作简化为上传文件会轻松很多;
降低错误率——人往往是出错的主要原因,让代码来记忆第一步操作可以大大降低出错机率;
版本控制——能够记录每一次配置的变更状况与时间,同时也更容易将配置恢复到某个时间点的备份;
快速部署——站点经不起长时间离线,将数周及数月的更新在数分钟基本数秒钟之内完成会有很爽的成就感;
……
Drupal 常见的配置迁移情况
之所以要谈配置迁移,是因为Web项目至少会有两个环境,即工程师的本地开发环境,和在线运行的生产环境。而通常情况下,标准的Web项目会涉及“开发-测试-线上”,即流行的 Dev-Stage-Prod 模型(也有称Dev-Stage-Live),复杂点的情况还会再加上一个QA环境。也正因为如此,才出现了配置迁移的需要。
在后文中,我们将以 Dev-Stage-Prod 环境模型为来了解 Drupal 的配置迁移方式及方向。因为这正好代表了我们平时的工作流程——工程师在各自的本地进行开发,然后部署到测试环境集中测试,反复修正最后再部署到线上。
Drupal 需要迁移哪些内容以及如何迁移
了解了需要迁移的原因,我们再看看需要迁移的内容。正如前面所说,Drupal 中不同的配置有不同的迁移方式,使用对的工具和对的方法能够达到事半功倍的效果。
迁移项 | 存储位置 | 迁移方式 |
模块、主题 | 模块、主题文件中 | 直接上传文件 |
环境变量 | 数据库中 | 结合 Features 结合 Strongarm 模块打包到文件,然后上传 |
视图、编辑器、内容类型、字段、区块 | 数据库中 | 使用 Features 及 Features Extra 等模块打包到文件,然后上传 |
*术语、用户等配置依赖内容 | 数据库中 | 可使用 Features, UUID 及 UUID Features 等模块打包到文件,然后上传。 但建议先添加到线上环境,然后将数据库下载到本地进行开发会更简单,详见下方 |
不要感觉要记很多东西似的,这里帮你整理一下 —— Drupal 的配置无非就是存在于文件和数据库中,存在文件中的配置很好处理,直接上传就行。而对于存在于数据库中的配置呢?很简单 —— 先转化成文件,然后上传文件。
在举例说明不同配置迁移的最佳实践前,建议大家一定记住下图——代码(配置)由下往上,数据库(内容)由上往下——这是团队协作的基本铁律,以便确保文件和数据库都是由新往旧的方向部署,从源头减少冲突的发生。
(很多人在协作时会问这样的问题,说“我在线上修改了视图的配置,然后线下更新了视图的配置文件,这样要怎么更新呢?”这就是典型因为协作流程不规范而产生的人为冲突,一旦按照规范能够约束文件(配置)、数据库(内容)的更新方向,这类问题基本上便不会出现了。)
回到文章开头提到的几个问题,现在再来看看这些配置迁移流程建议:
站点配置或其它变量迁移 – 使用 Features 模块,结合 Strongarm 模块将要跟踪的变量打包到文件中,然后按 Dev->Stage->Prod 的方向进行更新部署
区块配置迁移 – 使用 Features 模块,结合 Features Extra 模块,将区块的配置及内容打包到文件中,然后按 Dev->Stage->Prod 的方向进行更新部署
内容类型、字段、视图、输入格式、编辑器配置等 – 使用 Features 模块(必要时结合Strongarm)将配置打包到文件中,然后按 Dev->Stage->Prod 的方向进行更新部署
内容数据的更新 – 使用 Backup and Migrate 模块或其它方式导出线上环境的数据库,并按 Prod->Stage->Dev 的方向进行内容更新
Drupal 配置迁移小结
现在看来,Drupal的配置迁移无非是两部分的内容,一部分已经存在于文件(如模块、主题)中的内容,直接上传文件进行更新即可;另一部分存在于数据库中的部分配置(或内容),即通过Features及其它相关模块先将配置导出到文件中,再按更新文件的操作进行即可。
别看关于 Drupal 配置迁移好像写了不少,主要便是掌握 Features 模块的用法和流程,稍加练习几次就会发现真是非常简单。
1.单态设计模式含义:
单态模式的主要作用是保证在面向对象编程设计中,一个类只能有一个实例对象存在。作为对象的创建模式,单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统全局地提供这个实例。它不会创建实例副本,而是会向单例类内部存储的实例返回一个引用。
2.单台模式的三个关键点:
① 需要一个保存类的唯一实例的静态成员变量;
②构造函数和克隆函数必须声明为私有的,防止外部程序new类从而失去单例模式的意义;
③必须提供一个访问这个实例的公共的静态方法(通常为getInstance方法),从而返回唯一实例的一个引用 。
代码如下 | 复制代码 |
<?php class DB { private static $obj = null; //声明一个私有的,静态的成员属性$obj private function__construct() { //私有构造方法,只能在类的内部实例化对象 echo "连接数据库成功<br>"; } public static function getInstance() { // 通过此静态方法才能获取本类的对象 if(is_null(self::$obj)) //如果本类中的$obj为空,说明还没有被实例化过 self::$obj = new self(); //实例化本类对象 return self::$obj; //返回本类的对象 } public function query($sql) { //执行SQL语句完成对数据库的操作 echo $sql; } } $db = DB::getInstance(); //只能使用静态方法getInstance()去获取DB类的对象 $db -> query("select *from user"); //访问对象中的成员 ?> |
单例模式,就是保持一个对象只存在一个实例。并且为该唯一实例提供一个全局访问点(一般是一个静态的getInstance方法)。单例模式应用场景非常广泛,例如:
数据库操作对象
日志写入对象
全局配置解析对象等
这些场景的共同特征是从业务逻辑上来看运行期间改对象却是
只需要一个实例
不断new多个实例会增加不必要的资源消耗
全局调用便利
。
下面分别说明这三个方面:
1. 业务上只需要一个实例
以数据库连接对象为例,加入有一个购物网站,有一个MySQL数据库
127.0.0.1:3306
,那么在一个进程中无论我们需要进行多少次针对改数据库的操作,都只需要连接数据库一次,使用相同的数据库连接句柄(MySQL Connection Resource),从业务需求上来看就只需要一个实例。
相反,同样以购物网站为例,存在许多商品,这些商品都不一样(id,name,price..),这个时候需要显示一个商品列表,加入我们建立一个
Product
作为数据映射对象,那么从业务需求上来说,一个实例就无法满足业务需求,因为每个商品都不一样。
2. 不断new操作增加不必要的资源消耗
我们一般会在类的构造方法(new操作肯定会调用)中进行一些业务操作,例如数据库连接对象可能会在构造方法中尝试读取数据库配置并进行数据库连接(如mysqli::__construct())、日志写入对象会判断日志写入目录是否存在并写入(不存在可能尝试创建改目录)、全局配置解析对象可能需要定位配置文件的保存目录并进行文件扫描等。
这些业务都会消耗相当的资源,如果在一个进程中我们值需要做一次,将会非常有利于我们提高应用的运行效率。
3. 全局调用便利
因为单例模式的一大特点就是通过静态方法获取对象实例,那么就意味着访问对象的方法时不需要先new一个对象的实例,如果改对象需要很多地方使用,则提高了调用的便利性。
通过一个日志操作类来举例:
代码如下 | 复制代码 |
class Logger{ //首先,需要一个私有的静态变量来存储产生的对象实例 private static $instance; //业务变量,保存日志写入路径 private $logDir; //构造方法,注意必须也是私有的,不允许被外部实例化(即在外部被new) private function __construct(){ //调试输出,测试对象被new的次数 echo "new Logger instance rn"; $logDir = sys_get_temp_dir(). DIRECTORY_SEPARATOR . "logs"; if(!is_dir($logDir) || !file_exists($logDir)){ @mkdir($logDir); } $this->logDir = $logDir; } //类唯一实例的全局访问点,用于判断并返回对象实例,供外部调用 public static function getInstance(){ if(is_null(self::$instance)){ $class = __CLASS__; //获取本对象的类型,也可以用new self()方式 self::$instance = new $class(); } return self::$instance; } //重载__clone()方法,不允许对象对克隆 public function __clone(){ throw new Exception("Singleton Class Can Not Be Cloned"); } //具体的业务方法,实际可以有很多方法 public function logError($message){ $logFile = $this->logDir . DIRECTORY_SEPARATOR . "error.log"; error_log($message, 3, $logFile); } } //日志调用 $logger = Logger::getInstance(); $logger->logError("An error occured"); $logger->logError("Another error occured"); //或者这样调用 Logger::getInstance()->logError("Still have error"); Logger::getInstance()->logError("I should fix it"); |
在单例模式中可能遇到一种比较特殊的情况,比如数据库连接对象,对于大型应用来说,很可能需要连接多台数据库,那么不同的数据库公用一个对象可能会产生问题,比如连接的分配、获取
insert_id
,
last_error
等。这个问题也比较好解决,就是把我们的$instance变量变成一个关联数组,通过给getInstance方法传入不同的参数获取不同的"单例对象"(引号的含义是:严格来说类可能被new多次,但是这个new也是在我们的控制之内的,而不是在类外部):
代码如下 | 复制代码 |
class MysqlServer{ //注意,变成复数了哦^_^ 当然只是为了标识而已 private static $instances = array(); //业务变量,保持当前实例的mysqli对象 private $conn; //显著特征:私有的构造方法,避免在类外部被实例化 private function __construct($host, $username, $password, $dbname, $port){ $this->conn = new mysqli($host, $username, $password, $dbname, $port); } //类唯一实例的全局访问点 public static function getInstance($host='localhost', $username='root', $password='123456', $dbname='mydb', $port='3306'){ $key = "{$host}:{$port}:{$username}:{$dbname}"; if (empty(self::$instances[$key])){ //这里也可以用 new self(); 的方式 $class = __CLASS__; self::$instances[$key] = new $class($host, $username, $password, $dbname, $port); } return self::$instances[$key]; } //重载__clone方法,不允许对象实例被克隆 public function __clone(){ throw new Exception("Singleton Class Can Not Be Cloned"); } //查询业务方法,后面省略其它业务方法 public function query($sql){ return $this->conn->query($sql); } //尽早释放资源 public function __destruct(){ $this->conn->close(); } } |
问题1:单例类能否拥有子类,因为单例类的构造方法是私有的,因此无法被继承,如果要继承则需要将构造方法改为protected或public,这就违背了单例模式的本意。因此,如果你想给单例类加子类,那就需要回头想想是否错用了模式,或者结构设计上有问题。
问题2:单例滥用,单例模式相对来说比较好理解和实现,因此一旦认识到单例模式的好处,很可能什么类都想写成单例,因此在使用次模式之前一定要考虑上述3种情况,看是否真的有必要使用。
今天在个数据库类时一直都没法获取最后保存数据的ID了,经过反复排查还是没找到原因,不过后来总结了一些查找出mysql指定表中最后一条记录的ID或直接是说最新插入记录的ID,下面一起来看看。开发什么的最喜欢了。写程序可以提高实力又可以收藏一些代码!的确很是不错。由于某些原因需要获取数据库最大的id值。所以出现了这段php 获取数据库最大的id代码了。这里面的max(id) 这里面的id 就是要获取最大的id了。如果是别的字段请填写为其他字段
方法一
$fh = mysql_query("select MAX(id) from log");
$c_echo = mysql_fetch_array($fh);
echo $c_echo;
方法二
<?php
//执行插入数据库的语句
//……
$getID=mysql_insert_id();//$getID即为最后一条记录的ID
?>
PHP 函数 mysql_insert_id() 是返回在最后一次执行了 INSERT 查询后,由 AUTO_INCREMENT 定义的字段的值。
方法三
msyql_query("select last_insert_id()");
last_insert_id() 是mysql 一个函数 也是 对当前链接起效
此用法 解决了 mysql_insert_id () 中遇到的 bigint 型问题
使用PHP描述冒泡排序和快速排序算法,对象可以是一个数组。
使用PHP描述顺序查找和二分查找(也叫做折半查找)算法,顺序查找必须考虑效率,对象可以是一个有序数组。
写一个二维数组排序算法函数,能够具有通用性,可以调用php内置函数
1. 使用PHP描述冒泡排序和快速排序算法,对象可以是一个数组
代码如下 | 复制代码 |
function bubble_sort($array)
|
2. 使用PHP描述顺序查找和二分查找(也叫做折半查找)算法,顺序查找必须考虑效率,对象可以是一个有序数组
代码如下 | 复制代码 |
function bin_sch($array, $low, $high, $k){ if ($low <= $high){ $mid = intval(($low+$high)/2); if ($array[$mid] == $k){ return $mid; }elseif ($k < $array[$mid]){ return bin_sch($array, $low, $mid-1, $k); }else{ return bin_sch($array, $mid+1, $high, $k); } } return -1; }function seq_sch($array, $n, $k){ $array[$n] = $k; for($i=0; $i<$n; $i++){ if($array[$i]==$k){ break; } } if ($i<$n){ return $i; }else{ return -1; } } |
3. 写一个二维数组排序算法函数,能够具有通用性,可以调用php内置函数
代码如下 | 复制代码 |
function array_sort($arr, $keys, $order=0) { |
相关文章
- PHPEMS(PHP Exam Management System)在线模拟考试系统基于PHP+Mysql开发,主要用于搭建模拟考试平台,支持多种题型和展现方式,是国内首款支持题冒题和自动评分与教师评分相...2016-11-25
- SQL注入攻击指的是通过构建特殊的输入作为参数传入Web应用程序,而这些输入大都是SQL语法里的一些组合,通过执行SQL语句进而执行攻击者所要的操作 标准注入语句1.判...2016-11-25
- 防止SQL注入是我们程序开发人员必须要做的事情了,今天我们就来看一篇关于PHP防止SQL注入的例子了,具体的实现防过滤语句可以参考下面来看看吧。 使用prepared以及参...2016-11-25
- 什么是js跨域呐?js跨域是指通过js在不同的域之间进行数据传输或通信,比如用ajax向一个不同的域请求数据,或者通过js获取页面中不同域的框架中(iframe)的数据。只要协议、域名、端口有任何一个不同,都被当作是不同的域。要...2015-10-30
- 什么是js跨域呐?js跨域是指通过js在不同的域之间进行数据传输或通信,比如用ajax向一个不同的域请求数据,或者通过js获取页面中不同域的框架中(iframe)的数据。只要协议、域名、端口有任何一个不同,都被当作是不同的域。要...2015-10-30
- SQL注入攻击是黑客攻击网站最常用的手段。如果你的站点没有使用严格的用户输入检验,那么常容易遭到SQL注入攻击。SQL注入攻击通常通过给站点数据库提交不良的数据或...2016-11-25
- 本文章以自己的一些经验来告诉你黑客朋友们会怎么利用你数据库的sql漏洞来把你的数据库下载哦,有需要的同这参考一下本文章。 在数据库中建立一张表: 代码...2016-11-25
- 这篇文章主要介绍了ASP.NET防止SQL注入的方法,结合具体实例形式分析了asp.net基于字符串过滤实现防止SQL注入的相关操作技巧,需要的朋友可以参考下...2021-09-22
- 本文简单介绍如何防止外部恶意调用ajax接口,以达到节省流量,减轻服务器压力的目的。...2016-04-15
- 这两天项目开发中,需要实现一些比较实用的功能,用了两个使用的sql,总结一下,怕下次忘记了。 1. 检索数据库中跟提交的内容相匹配的内容 比如:提交的数据是“游...2016-11-25
- 重复提交数据我们在应用中经常会碰到了,今天我给各位介绍利用session来防止用户不小心重复提交数据的一个例子 原理非常的简单:就是用session在表单页面记录下,...2016-11-25
- SQL注入是一种攻击,允许攻击者增加额外的逻辑表达式和命令,以现有的SQL查询,种攻击能够成功每当用户提交的数据是不正确验证,并粘有一个合法的SQL查询在一起,所以说sql注...2016-11-25
- 如何设计出简单易用的网页?今天小编要说的 10 个简化技巧都是围绕着这个思路来推进的。无论你是正在设计一个全新的网站,还是针对现有的网站进行简化,这 10 个简化技巧都...2017-07-06
- 文件锁可以防止文件读写时多人访问时出现共享问题或数据不准确的问题,下面我们来看一篇关于php文件锁类防止并发的例子,具体如下. 工作间隙写了个文件锁的类,用于...2016-11-25
- MYSQL用户ROOT密码为空时是一个很大的漏洞,在网上也有许多一些利用此漏洞的方法,一般就是写一个ASP或PHP的后门,不仅很麻烦,而且还要猜解网站的目录,如果对方没有开IIS,那我...2016-11-25
- 本篇文章是对用checked语句防止数据溢出的解决方法进行了详细的分析介绍,需要的朋友参考下...2020-06-25
- //echo fn(4); echo fn2(4); //n! = 1* 2 * 3 * ... n function fn($n){ if($n == 0) return 1; $fn = 1; for($i = 1; $i <= $n ; $i++){ $fn *= $i;...2016-11-25
- [转]SQL 注入 SQL 注入 很多 web 开发者没有注意到 SQL 查询是可以被篡改的,因而把 SQL 查询当作可信任的命令。殊不知道,SQL 查询可以绕开访问控制,从而绕过身份验证和...2016-11-25
- 1、PHP加密解密PHP加密和解密函数可以用来加密一些有用的字符串存放在数据库里,并且通过可逆解密字符串,该函数使用了base64和MD5加密和解密。function encryptDecrypt($key, $string, $decrypt){ if($decrypt){...2015-10-23
- 在本系列文章中,我们将全面探讨如何在PHP开发环境中全面阻止SQL注入式攻击,并给出一个具体的开发示例。 一、 引言 PHP是一种力量强大但相当容易学习...2016-11-25