这个框架功能比较简单,只有url拦截及自定义、加载静态模板两个功能,之前的博客也是基于这个框架实现的。第一部分是记录实现这个框架所需的php基础知识,第二部分是这两个功能的实现方法。最后还有实现自动登录的最佳实践。
php基础相关
$_SERVER
服务器和执行环境信息
几个用到的项: * 'REQUEST_METHOD'
: 访问页面使用的请求方法;例如,“GET”
,“HEAD”
,“POST”
,“PUT”
。 * 'REQUEST_URI'
: URI 用来指定要访问的页面。例如 “/index.html”
。
Date
1 | date(format,timestamp) |
:--- | : --- |
format | 必需。规定如何返回结果。|
timestamp | 可选。 |
格式化方式说明
格式化方式 | 说明 |
---|---|
Y | 4位数字年,y为2位数字,如99即1999年 |
m | 数字月份,前面有前导0,如01。n 为无前导0数字月份 |
F | 月份,完整的文本格式,例如 January 或者 March |
M | 三个字母缩写表示的月份,例如 Jan 或者 Mar |
d | 月份中的第几天,前面有前导0,如03。j 为无前导0的天数 |
w | 星期中的第几天,以数字表示,0表示星期天 |
z | 年份中的第几天,范围0-366 |
W | 年份中的第几周,如第32周 |
H | 24小时格式,有前导0,h为12小时格式 |
G | 24小时格式,无前导0,g为对应12小时格式 |
i | 分钟格式,有前导0 |
s | 秒格式,有前导0 |
A | 大写上下午,如AM,a为小写 |
例子 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
echo("Result with date():<br />");
echo(date("l") . "<br />");
echo(date("l dS \of F Y h:i:s A") . "<br />");
echo("Oct 3,1975 was on a ".date("l", mktime(0,0,0,10,3,1975))."<br />");
echo(date(DATE_RFC822) . "<br />");
echo(date(DATE_ATOM,mktime(0,0,0,10,3,1975)) . "<br /><br />");
echo("Result with gmdate():<br />");
echo(gmdate("l") . "<br />");
echo(gmdate("l dS \of F Y h:i:s A") . "<br />");
echo("Oct 3,1975 was on a ".gmdate("l", mktime(0,0,0,10,3,1975))."<br />");
echo(gmdate(DATE_RFC822) . "<br />");
echo(gmdate(DATE_ATOM,mktime(0,0,0,10,3,1975)) . "<br />");
结果: > Result with date()
: Tuesday Tuesday 24th of January 2006 02:41:22 PM Oct 3,1975 was on a Friday Tue, 24 Jan 2006 14:41:22 CET 1975-10-03T00:00:00+0100
Result with
gmdate()
: Tuesday Tuesday 24th of January 2006 01:41:22 PM Oct 3,1975 was on a Thursday Tue, 24 Jan 2006 13:41:22 GMT 1975-10-02T23:00:00+0000
字符串
explode()
分割字符串,返回数组。 1
explode(delimiter, string)
随机字符串
- 预置一个的字符串 $chars ,包括 a – z,A – Z,0 – 9,以及一些特殊字符。
- 在 $chars 字符串中随机取一个字符。
- 重复第二步n次,可得长度为n的字符串。
1 | function generate_password( $length = 8 ) { |
加密
sha256 1
$password = hash('sha256', $identifier . $_POST['password']);
Session
每次用之前一定要session_start()
: 1
2session_start();
$_SESSION[$var] = xxxx;
setcookie()
函数用于设置 cookie。
语法 1
setcookie(name, value, expire, path, domain);
例子 在下面的例子中,我们将创建名为 "user" 的 cookie,把为它赋值 "Alex Porter"。我们也规定了此 cookie 在一小时后过期: 1
2
3
4
5
6
7
8
9
setcookie("user", "Alex Porter", time()+3600);
<html>
<body>
</body>
</html>
注释:在发送 cookie 时,cookie 的值会自动进行 URL 编码,在取回时进行自动解码(为防止 URL 编码,请使用
setrawcookie()
取而代之)。
PHP 的$_COOKIE
变量用于取回 cookie 的值。 在下面的例子中,我们取回了名为 "user"
的 cookie 的值,并把它显示在了页面上: 1
2
3
4
5
6
7
// Print a cookie
echo $_COOKIE["user"];
// A way to view all cookies
print_r($_COOKIE);
当删除 cookie 时,您应当使过期日期变更为过去的时间点。 删除的例子: 1
2
3
4
// set the expiration date to one hour ago
setcookie("user", "", time()-3600);
变参
1 |
|
反射
建立反射类
1 | $class = new ReflectionClass('Person');//建立 Person这个类的反射类 |
获取属性(Properties)
1 | $properties = $class->getProperties(); |
获取注释
1 | foreach($properties as $property) { |
获取类的方法
1 | if($class->hasMethod($methodName)){ |
执行类的方法
1 | $instance->getBiography(); //执行Person 里的方法getBiography |
URI
uri结构:
apppath/class/method/params
uri示例 :www.liuhe.website/index.php?/Articles/single/13
实现方法:
- 在
index.php
中通过$_SERVER['REQUEST_URI']
获取uri,然后获取className
,methodName
以及params
。 - include相应控制器的文件,即
controller/$className.php
。 - 建立反射类,调用相关method传入相应参数。
- 防止直接通过文件目录访问(通过服务器配置rewrite实现)
code: 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58/**
* Parse uri , instantiate the class
* and invoke the method
*/
public function parseRequestUri()
{
if (isset($_SERVER['REQUEST_URI'])) {
$this->uri_string = $_SERVER['REQUEST_URI'];
$this->segments = explode('/', $this->uri_string);
// var_dump($this->segments);
/*
* get the class name, method name and the params
*/
if (count($this->segments) <= 2) {
$className = 'Articles';
$methodName = 'home';
} else {
$className = $this->segments[2];
if (isset($this->segments[3])) {
$methodName = $this->segments[3];
} else {
// 404 Error
$this->_404Error("Empty Method");
}
}
if ($_SERVER['REQUEST_METHOD'] == 'GET' || $_SERVER['REQUEST_METHOD'] == 'POST') {
$params = array();
$len = count($this->segments);
if ($len > 4) {
for ($i = 4; $i < $len; $i++) {
array_push($params, $this->segments[$i]);
}
}
$classFile = "controller/$className.php";
if (!file_exists($classFile)) {
// 404 error
$this->_404Error("File Not Found");
return;
}
/*
* build reflection class, invoke the method
*/
require "$classFile";
$rc = new ReflectionClass($className);
if (!$rc->hasMethod($methodName)) {
// 404 error
$this->_404Error("Method Not Found");
return;
}
$instance = $rc->newInstance();
$method = $rc->getMethod($methodName);
$method->invokeArgs($instance, $params);
}
} else {
echo "not set REQUEST_URI";
return;
}
}
加载静态模板(带参数)
实现方法: * 定义参数结构(占位符): * i 为第i个参数 * 把模板文件加载到内存,用字符串替换函数替换上述占位符。
code: 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22/**
* Load a static template
*
* @var string, array
*/
public function load($page = '', $args = array())
{
if (empty($page)) {
return;
}
$fileName = "static/$page";
$file = fopen($fileName, "r");
$content = fread($file, filesize($fileName));
if (!empty($args)) {
$i = 0;
while (strpos($content, "{{args[$i]}}") !== false) {
$content = str_replace("{{args[$i]}}", $args[$i], $content);
$i += 1;
}
}
echo "$content";
}
实现自动登录
以下部分来自StackOverflow
- When the user successfully logs in with Remember Me checked, a login cookie is issued in addition to the standard session management cookie.
- The login cookie contains a series identifier and a token. The series and token are unguessable random numbers from a suitably large space. Both are stored together in a database table, the token is hashed (sha256 is fine).
- When a non-logged-in user visits the site and presents a login cookie, the series identifier is looked up in the database.
- If the series identifier is present and the hash of the token matches the hash for that series identifier, the user is considered authenticated. A new token is generated, a new hash for the token is stored over the old record, and a new login cookie is issued to the user (it's okay to re-use the series identifier).
- If the series is present but the token does not match, a theft is assumed. The user receives a strongly worded warning and all of the user's remembered sessions are deleted.
- If the username and series are not present, the login cookie is ignored.
This approach provides defense-in-depth. If someone manages to leak the database table, it does not give an attacker an open door for impersonating users.