原创部分:
原因 :有多种,我遇到的是因为文件编码的问题,个别文件在保存时,保留了UTF-8 POM(windows 的问题?)
解决:
使用PhpStorm上下文菜单项的[remove POM],去除utf-8头标识,避免意外的响应输出。
答案:
class ECS
{
var $db_name = '';
var $prefix = 'ecs_';
/**
* 构造函数
*
* @access public
* @param string $db_name 数据库名
* @param string $prefix 表前缀
*
*/
function __construct($db_name, $prefix)
{
$this->db_name = $db_name;
$this->prefix = $prefix;
}
注意
构造函数在php doc中的说明,返回值 return value 不再是void, 注意拼写,不是 __constructor
不再用类名同名函数, 且默认不调父类构造方法,需要时手动调用parent::__construct(…)
这篇文章主要介绍了PHP正则替换函数preg_replace和preg_replace_callback
使用总结,本文是在写一个模板引擎遇到一个特殊需求时总结而来,需要的朋友可以参考下
在编写PHP模板引擎工具类时,以前常用的一个正则替换函数为 preg_replace(),加上正则修饰符 /e,就能够执行强大的回调函数,实现模板引擎编译(其实就是字符串替换)。
详情介绍参考博文:PHP函数preg_replace
正则替换所有符合条件的字符串
应用举例如下:
/**
* 模板解析类
*/
class Template {
public function compile($template) {
// if逻辑
$template = preg_replace("/\<\!\-\-\{if\s+(.+?)\}\-\-\>/e", "\$this->ifTag('\\1')", $template);
return $template;
}
/**
* if 标签
*/
protected function ifTag($str) {
//$str = stripslashes($str); // 去反转义
return ' . $str . ') { ?>';
}
}
$template = 'xxxyyyzzz';
$tplComplier = new Template();
$template = $tplComplier->compile($template);
echo $template;
?>
password_hash已经有加盐的功能了,不需要再额外手工处理了
try{
// 创建连接
// 你可能需要将第一个参数年 hostname 替换为 localhost.
// 注意我们是如何声明字符集 utf8mb4 的. This alerts the connection that we'll be passing UTF-8 data. This may not be required depending on your configuration, but it'll save you headaches down the road if you're trying to store Unicode strings in your database. See "Gotchas".
// The PDO options we pass do the following:
// \PDO::ATTR_ERRMODE enables exceptions for errors. This is optional but can be handy.
// \PDO::ATTR_PERSISTENT disables persistent connections, which can cause concurrency issues in certain cases. See "Gotchas".
$link = new \PDO( 'mysql:host=your-hostname;dbname=your-db;charset=utf8mb4',
'your-username',
'your-password',
array(
\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION,
\PDO::ATTR_PERSISTENT => false
)
);
$handle = $link->prepare('select Username from Users where UserId = ? or Username = ? limit ?');
// PHP bug: 如果不指明 PDO::PARAM_INT, PDO 有可能会对参数加引号. 从需引起 MySQL 查询的混乱,整型数据是不应加引号的.
// 参见: https://bugs.php.net/bug.php?id=44639
// 如果不清楚传进来的参数是否为整型, 可以用 is_int() 函数来判断.
// 这个bug已在 2016年10月解决, 但早一点的版本都会受影响 PHP ; [参见](https://bugs.php.net/bug.php?id=73234)
$handle->bindValue(1, 100, PDO::PARAM_INT);
$handle->bindValue(2, 'Bilbo Baggins');
$handle->bindValue(3, 5, PDO::PARAM_INT);
$handle->execute();
// Using the fetchAll() method might be too resource-heavy if you're selecting a truly massive amount of rows.
// If that's the case, you can use the fetch() method and loop through each result row one by one.
// You can also return arrays and other things instead of objects. See the PDO documentation for details.
$result = $handle->fetchAll(\PDO::FETCH_OBJ);
foreach($result as $row){
print($row->Username);
}
}
catch(\PDOException $ex){
print($ex->getMessage());
}
?>
注意
1. 整型绑定如果不用PDO::PARAM_INT指定类型, 有时会被引号括起来 参见;
2. 连接字符串不要用utf8mb4编码,会不正确存储数据,取决于数据库配置;
3. 声明utf8mb4字符集还要确保数据表也是用的utf8mb4,为什么用utf8mb4面不是utf8可以参见php有关UTF-8部分;
4. 可持久化连接可能会造成并发问题,这不是php的问题,这是应用层的问题,见Stack Overflow question;
5. 单次方法 execute() 调用可以执行多条sql语句,语句间分号分隔即可,在低版本上可能有问题.
使用 , = ?>
, 其他的取决于配置,不建议用。
注意
?>后的回车会造成纯php类文件产生输出,进而后续的修改http header后产生错误
文件开头也要避免
php 支持对未加载的类文件自动加载机制,旧的办法是调用 __autoload(), 新机制是通过spl_autoload_register 进行注册自动加载函数。
// First, define your auto-load function.
function MyAutoload($className){
include_once($className . '.php');
}
// Next, register it with PHP.
spl_autoload_register('MyAutoload');
// Try it out!
// Since we haven't included a file defining the MyClass object, our auto-loader will kick in and include MyClass.php.
// For this example, assume the MyClass class is defined in the MyClass.php file.
$var = new MyClass();
?>
不用顾及解不解析的差异
这两种方法定义常量略有区别
define() 在运行时定义常量, 而 const 是在编译时. 所以 const 稍快一点, 除非软件超大,否则可忽略这个差别.
define() 常量放在全局域, 可引入特定的命名空间. 不能用 define() 定义类的常量.
define() 定义的常量名和值都可以用表达式, const 则都不行. define() 在这点上更灵活.
define() 可以在 if() 块中用, const 不行.
// Let's see how the two methods treat namespaces
namespace MiddleEarth\Creatures\Dwarves;
const GIMLI_ID = 1;
define('MiddleEarth\Creatures\Elves\LEGOLAS_ID', 2);
echo(\MiddleEarth\Creatures\Dwarves\GIMLI_ID); // 1
echo(\MiddleEarth\Creatures\Elves\LEGOLAS_ID); // 2; note that we used define(), but the namespace is still recognized
// Now let's declare some bit-shifted constants representing ways to enter Mordor.
define('TRANSPORT_METHOD_SNEAKING', 1 << 0); // OK!
const TRANSPORT_METHOD_WALKING = 1 << 1; // Compile error! const can't use expressions as values
// Next, conditional constants.
define('HOBBITS_FRODO_ID', 1);
if($isGoingToMordor){
define('TRANSPORT_METHOD', TRANSPORT_METHOD_SNEAKING); // OK!
const PARTY_LEADER_ID = HOBBITS_FRODO_ID // Compile error: const can't be used in an if block
}
// Finally, class constants
class OneRing{
const MELTING_POINT_CELSIUS = 1000000; // OK!
define('MELTING_POINT_ELVISH_DEGREES', 200); // Compile error: can't use define() within a class
}
?>
php内置缓存字节码的功能,无需操心
低版本的还是升级吧,或用[APC](sudo apt-get install php-apc)
需要分布式缓存用[Memcached](sudo apt-get install php5-memcached), 否则可以考虑用 [APCu](sudo apt-get install php5-apcu)
// Store some values in the APCu cache. We can optionally pass a time-to-live, but in this example the values will live forever until they're garbage-collected by APCu.
apc_store('username-1532', 'Frodo Baggins');
apc_store('username-958', 'Aragorn');
apc_store('username-6389', 'Gandalf');
// You can store arrays and objects too.
apc_store('creatures', array('ent', 'dwarf', 'elf'));
apc_store('saruman', new Wizard());
// After storing these values, any PHP script can access them, no matter when it's run!
$value = apc_fetch('username-958', $success);
if($success === true)
print($value); // Aragorn
$value = apc_fetch('creatures', $success);
if($success === true)
print_r($value);
$value = apc_fetch('username-1', $success); // $success will be set to boolean false, because this key doesn't exist.
if($success !== true) // Note the !==, this checks for true boolean false, not "falsey" values like 0 or empty string.
print('Key not found');
apc_delete('username-958'); // This key will no longer be available.
?>
请使用 PCRE ( preg_* ) 一族方法,不要用 POSIX (POSIX 扩展, ereg_* ) 方法.
请使用 PHP-FPM.
安装
sudo apt-get install apache2-mpm-event libapache2-mod-fastcgi php5-fpm
sudo a2enmod actions alias fastcgi
使用
Require all granted
Action php5-fcgi /php5-fcgi
Alias /php5-fcgi /usr/lib/cgi-bin/php5-fcgi
FastCgiExternalServer /usr/lib/cgi-bin/php5-fcgi -socket /var/run/php5-fpm.sock -idle-timeout 120 -pass-header Authorization
SetHandler php5-fcgi
sudo service apache2 restart && sudo service php5-fpm restart
注意
用AddHandler 指令替代 SetHandler 会有一定的风险,AddHandler 会让任何地方的php代码得到执行,如evil.php.gif
## 发邮件
使用 PHPMailer,强于内置的mail函数
// Include the PHPMailer library
require_once('phpmailer-5.2.7/PHPMailerAutoload.php');
// Passing 'true' enables exceptions. This is optional and defaults to false.
$mailer = new PHPMailer(true);
// Send a mail from Bilbo Baggins to Gandalf the Grey
// Set up to, from, and the message body. The body doesn't have to be HTML; check the PHPMailer documentation for details.
$mailer->Sender = '[email protected]';
$mailer->AddReplyTo('[email protected]', 'Bilbo Baggins');
$mailer->SetFrom('[email protected]', 'Bilbo Baggins');
$mailer->AddAddress('[email protected]');
$mailer->Subject = 'The finest weed in the South Farthing';
$mailer->MsgHTML('You really must try it, Gandalf!
-Bilbo
');
// Set up our connection information.
$mailer->IsSMTP();
$mailer->SMTPAuth = true;
$mailer->SMTPSecure = 'ssl';
$mailer->Port = 465;
$mailer->Host = 'my smtp host';
$mailer->Username = 'my smtp username';
$mailer->Password = 'my smtp password';
// All done!
$mailer->Send();
?>
见
使用 filter_var() 函数
filter_var('[email protected]', FILTER_VALIDATE_EMAIL); // Returns "[email protected]". This is a valid email address.
filter_var('sauron@mordor', FILTER_VALIDATE_EMAIL); // Returns boolean false! This is *not* a valid email address.
?>
使用 htmlentities() 函数,可指定标签的白名单
strip-tags 函数虽然简单,但不保证html语义正确,处理不好标签闭合的问题。
filter-var 函数处理不了换行的问题
简单情况, 转义
// Oh no! The user has submitted malicious HTML, and we have to display it in our web app!
$evilHtml = 'Mua-ha-ha! Twiddling my evil mustache...';
// Use the ENT_QUOTES flag to make sure both single and double quotes are escaped.
// Use the UTF-8 character encoding if you've stored the text as UTF-8 (as you should have).
// See the UTF-8 section in this document for more details.
$safeHtml = htmlentities($evilHtml, ENT_QUOTES, 'UTF-8'); // $safeHtml is now fully escaped HTML. You can output $safeHtml to your users without fear!
?>
复杂情况,清洗
// Include the HTML Purifier library
require_once('htmlpurifier-4.6.0/HTMLPurifier.auto.php');
// Oh no! The user has submitted malicious HTML, and we have to display it in our web app!
$evilHtml = 'Mua-ha-ha! Twiddling my evil mustache...';
// Set up the HTML Purifier object with the default configuration.
$purifier = new HTMLPurifier(HTMLPurifier_Config::createDefault());
$safeHtml = $purifier->purify($evilHtml); // $safeHtml is now sanitized. You can output $safeHtml to your users without fear!
?>
可以在 mb_internal_encoding() 在文件头上用,, mb_http_output() 设置页面输出格式
htmlentities() 应该明确指定用 UTF-8 编码。
// Tell PHP that we're using UTF-8 strings until the end of the script
mb_internal_encoding('UTF-8');
// Tell PHP that we'll be outputting UTF-8 to the browser
mb_http_output('UTF-8');
// Our UTF-8 test string
$string = 'Êl síla erin lû e-govaned vîn.';
// Transform the string in some way with a multibyte function
// Note how we cut the string at a non-Ascii character for demonstration purposes
$string = mb_substr($string, 0, 15);
// Connect to a database to store the transformed string
// See the PDO example in this document for more information
// Note that we define the character set as utf8mb4 in the PDO connection string
$link = new \PDO( 'mysql:host=your-hostname;dbname=your-db;charset=utf8mb4',
'your-username',
'your-password',
array(
\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION,
\PDO::ATTR_PERSISTENT => false
)
);
// Store our transformed string as UTF-8 in our database
// Your DB and tables are in the utf8mb4 character set and collation, right?
$handle = $link->prepare('insert into ElvishSentences (Id, Body) values (?, ?)');
$handle->bindValue(1, 1, PDO::PARAM_INT);
$handle->bindValue(2, $string);
$handle->execute();
// Retrieve the string we just stored to prove it was stored correctly
$handle = $link->prepare('select * from ElvishSentences where Id = ?');
$handle->bindValue(1, 1, PDO::PARAM_INT);
$handle->execute();
// Store the result into an object that we'll output later in our HTML
$result = $handle->fetchAll(\PDO::FETCH_OBJ);
?>
"UTF-8" />
UTF-8 test page
foreach($result as $row){
print($row->Body); // This should correctly output our transformed UTF-8 string to the browser
}
?>
使用 DateTime 类, 不要再用 date(), gmdate(), date_timezone_set(), strtotime() 这些函数了
// Construct a new UTC date. Always specify UTC unless you really know what you're doing!
$date = new DateTime('2011-05-04 05:00:00', new DateTimeZone('UTC'));
// Add ten days to our initial date
$date->add(new DateInterval('P10D'));
echo($date->format('Y-m-d h:i:s')); // 2011-05-14 05:00:00
// Sadly we don't have a Middle Earth timezone
// Convert our UTC date to the PST (or PDT, depending) time zone
$date->setTimezone(new DateTimeZone('America/Los_Angeles'));
// Note that if you run this line yourself, it might differ by an hour depending on daylight savings
echo($date->format('Y-m-d h:i:s')); // 2011-05-13 10:00:00
$later = new DateTime('2012-05-20', new DateTimeZone('UTC'));
// Compare two dates
if($date < $later)
echo('Yup, you can compare dates using these easy operators!');
// Find the difference between two dates
$difference = $date->diff($later);
echo('The 2nd date is ' . $difference->days . ' later than 1st date.');
?>
注意
如果没设时区的话,DateTime::__construct()会设置与主机一样的时区
创建时间时,最好明确指出 UTC 时区,在 DateTime::__construct() 使用 Unix timestamp 时,时区会是UTC,与第二个参数无关。
“0000-00-00” 对DateTime::__construct()没有意义,不会产生 MySql期待的“0000-00-00”.
DateTime::getTimestamp() 在 32-位系统上只能表示 2038 年以前的日期. 64-位系统上OK.
使用 === 操作符检查是否为 null 和布尔 false 值.
$x = 0;
$y = null;
// Is $x null?
if($x == null)
print('Oops! $x is 0, not null!');
// Is $y null?
if(is_null($y))
print('Great, but could be faster.');
if($y === null)
print('Perfect!');
// Does the string abc contain the character a?
if(strpos('abc', 'a'))
// GOTCHA! strpos returns 0, indicating it wishes to return the position of the first character.
// But PHP interpretes 0 as false, so we never reach this print statement!
print('Found it!');
//Solution: use !== (the opposite of ===) to see if strpos() returns 0, or boolean false.
if(strpos('abc', 'a') !== false)
print('Found it for real this time!');
?>
注意
对于这种既可能返回0,又可能返回false的函数,如 strpos(), 请始终用 === 操作符,或 !== 操作符。