设置cookie的方法以下哪种方式无效?( )
A: setcookie(key,value); B: $_COOKIE['username']="Chloe"; C: setrawcookie(); D:header('Set-cookie:a=4');
oop self 关键字的作用包括哪些?( ) 多选
A: self是类内部代替类名的关键字; B: self可以完成类成员方法与调用类的动态绑定 C: self可以用来在类内部完成静态成员的访问(包括类常量); D: self可以在类内部来实例化对象
PHP全局成员不包括以下哪项( )
A: 函数; B: 常量; C: 变量; D: 类
PHP类定义中不支持的访问控制是( )
A: public; B: protected; C:private ; D: friend
以下不属于PHP标签的是: ( )
A: <?= ?>; B: < >; C:<? ?> ; D: <?php ?>
第一题:B,cookie设置目前只有setcookie、setrawcookie和header三种方法
第二题:ACD,static是完成调用类绑定
第三题:C,PHP全局成员有常量、函数、类(接口)
第四题:D,friend是C++的
第五题:B
执行pdo对象中的exec()方法可以获取到PDOStatement对象。( )
sessionID是存在客户端cookie中的。( )
php.ini文件中开启了session,会与引入第三方代码中的session_start()冲突。( )
explode()函数可以完成数组转字符串的功能。( )
PHP重载是指通过魔术方法动态地创建类属性和方法。( )
第一题:错,返回影响记录的行数
第二题:对
第三题:对,sessioin_start()会产生新的 session_id。
第四题:错,它是字符串转数组,implode是数组转字符串
第五题:对,
MySQL服务器的默认连接端口是_;
访问静态成员可以通过_和_完成;
PHP中跳出当前循环的语句是_, 跳过当前循环的语句是_;
面向对象的主要特征有_ and _ and _;
任何在composer.json文件中的修改都要执行__命令才能生效;
服务容器被誉为自动产生类/对象的工厂,服务容器的三要素是_ , __ and _;
我们可以通过__获取带有命名空间的类的完全限定名称;
MYSQL数据库查询操作中可以使用_字句指定查询结果的排序规则;
PHP命名空间中的use关键字有两种功能,分别是_and_;
psr-4规范是指将_与_进行绑定实现类的批量注册;
第一题:3306
第二题:self和static
第三题:break,continue
第四题:封装、继承和多态
第五题:composer dump-autoload
第六题:对象数组、绑定方法bind和获取方法make
第七题:类名::class
第八题:order by
第九题:引入命名空间的类和为命名空间的类取别名
第十是:命名空间和类所在的目录
答:PHP的回调函数也称为匿名函数或闭包Closure,主要应用场景有两个,一是内置函数提供了用户自定义处理机会,如array_map、array_reduce等数组函数,filter_var等过滤器函数,spl_autoload_register类拦截函数。另一个就是处理异步任务,说实在话,PHP本身对异步支持不友好,可通过swoole实现异步、并行的能力。回调函数使用外部变量可以使用普通函数两种形式:global关键字、$GLOBALS,PHP也提供了回调函数独有的形式:use。回调函数可以作为闭包Closure作为参数注入到函数中,可以给用户提供自定义处理的机会,另外call_user_func和call_user_func_array可调用普通函数或回调函数
答:页面间传值,目前我遇到主要有五种:
1、是url携带参数,如index.php?id=12&name=xiaoyao
2、是form表单提交数据,<form action="login.php" method="get">...</from>
3、ajax、fetch或axios与后端交互。
`$.ajax({
type: 'POST',
url: url,
data: data,
dataType: dataType,
success: function () {},
error: function () {}
});
4、cookie,setcookie('id',234);
5、session,$_SESSION['name']='xiaoyao
答:先完成PDO连接,然后进行query查询,exec增加、修改和删除操作。
$dsn="mysql:host=localhost;dbname=test;charset=utf8";
try{
$pdo=new PDO($dsn,'root','root');
// 原生查询
$sql="select * from user";
$res=$pdo->query($sql);
if($res) print_r($res->fetchAll(PDO::FETCH_ASSOC));
// 增加、更新和删除
$sql="insert into user(uname,pwd) values('junren',md5('12321321'))";
// $sql="update user set uname='haoren' where id=2";
// $sql="delete from user where id=1";
$res=$pdo->exec($sql);
if(!empty($res)) echo "成功操作{$res}条数据";
$pdo=null;
} catch (Exception $e){
die("数据库连接失败,原因是:".$e->getMessage());
}
$this,self::,static::,parent::
等关键字?答:四者都只能在类内使用,不同可分下面几种情况:
$this
常访问非静态成员,self::和static::
一般访问静态成员和常量,而parent::
即可访问静态成员和常量,又可访问非静态方法,不可访问非静态属性。$this和static::
绑定调用类,self::
绑定声明类,parent::
绑定父类。$this
常用于类内调用非静态成员,父类中常用static::
替代self::
,可解决单例继承问题,而parent::
常用扩展父类功能,如提供防登录欺骗等检查功能 实例演示区别(其中self、static和parent区别是基于PHP官方代码进行扩展的):
// $this
class Animal{
function test(){
return $this;
}
function who(){
echo __METHOD__.'<br>';
}
}
class Bird extends Animal{
}
$obj=new Bird();
var_dump($obj->test());//虽然test是Animal类成员方法,但是返回的是Bird类对象,即是调用类实例对象
// 上面本以为返回Animal类对象呢,结果却是B类。这点要和静态成员继承区分开,非静态成员是真继承即内置了父类的成员,而静态则是虚继承,它是共享的,最终调用还是要到父类中成员
// self、static和parent
class A{
static function foo(){
echo static::who();
}
static function who(){
echo __CLASS__.'<br>';
}
}
class B extends A{
static function test(){
A::foo();
// static是从调用类开始查找成员
parent::foo();
self::foo();
// self是本类开始查找成员,而parent是从父类查找成员
parent::who();
self::who();
}
static function who(){
echo __CLASS__.'<br>';
}
}
class C extends B{
// static function who(){
// echo __CLASS__.'<br>';
// }
}
C::test(); //输出是A B B A B
答:
第一种是传统类加载方式,就是使用require或include引入类文件,如include_once './demo.php'
,其中路径可是绝对路径,也可是相对路径,一般建议是相对路径,还有就是正反斜杠,由于是文件路径,在windows平台是正反斜杠都可以,若是Linux或MaxOS则要使用正斜杠。
// 第一种类加载方式:require或include传递加载类文件
include_once '.\demo.php';
C::test();
第二种是spl_autoload_register类拦截加载
// 第二种类拦截加载:spl_autoload_register
// 要求类名和文件名要相同,比较适合psr-4规范
spl_autoload_register(function ($classname) {
$path = __DIR__ . DIRECTORY_SEPARATOR . $classname . '.php';
echo $path;
if (is_file($path)) include_once $path;
});
C::test();
第三种是composer自动加载器加载类,在使用前引入vendor/autoload.php
,然后在composer.json增加autoload字段,可以采用三种方式:files加载类文件、classmap加载类文件目录,psr-4加载命名空间对应的类目录,不过最后一种建议是应用于命名空间的类,若是全局空间的类由于不符合psr-4规范,所以加载不了。修改composer.json后要调用composer dump-autoload使其生效。
include_once './vendor/autoload.php';
C::test();
//files加载类文件
"autoload": {
"files": [
"c.php"
]
},
//classmap加载类目录
"autoload": {
"classmap": [
".\\"
]
},
// psr-4加载只适合符合其规范的,下面是全局空间,加载是失败的
"autoload": {
"psr-4":{
"\\":"./"
}
},
/**
* 总体思路
* 1、form表单提交两个数和操作符
* 2、通过Get获取用户输入数据,进行判断是否合法,如除法时除数不能为0
* 3、合法则计算结果并返回给用户
*/
extract($_POST);
// var_dump(get_defined_vars());
$res = '';
// 用户提供进行计算
if ($btn === 'btn') {
if ($opt === '4' || $opt === '5') {
if (empty($num2)) $res = '除法或求余时,第二个数不能为0或空';
}
switch ($opt):
case '1':
$res=''.(intval($num1)+intval($num2));
break;
case '2':
$res=''.(intval($num1)-intval($num2));
break;
case '3':
$res=''.(intval($num1)*intval($num2));
break;
case '4':
if (empty($num2)) break;
$res=''.(intval($num1)/intval($num2));
break;
case '5':
if (empty($num2)) break;
$res=''.(intval($num1)%intval($num2));
break;
default:
$res = '运算符不合法,无法计算';
endswitch;
}
?>
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>PHP实现简单计算器</title>
</head>
<body>
<form action="calculator.php" method="POST">
<label for="num1">第一个数:</label>
<input type="number" name="num1" id="num1" value="<?php echo $num1; ?>" step="1">
<select name="opt">
<option value="1" <?php if ($opt == '1') echo 'selected'; ?>>+</option>
<option value="2" <?php if ($opt == '2') echo 'selected'; ?>>-</option>
<option value="3" <?php if ($opt == '3') echo 'selected'; ?>>*</option>
<option value="4" <?php if ($opt == '4') echo 'selected'; ?>>/</option>
<option value="5" <?php if ($opt == '5') echo 'selected'; ?>>%</option>
</select>
<label for="num2">第二个数:</label>
<input type="number" name="num2" id="num2" value="<?php echo $num2; ?>" step="1">
<button name="btn" value="btn">计算</button>
</form>
<div class="msg">
<p>计算结果:<span><?php echo $res; ?></span></p>
</div>
</body>
</html>
答:客户端cookie记录用户sessionID,并设置令牌和有效期,服务器端session同时保存了令牌和有效期,通过客户端令牌可以查询是否合法用户,从而完成自动登录
//index.php
<?php
session_start();
// 1、检测cookie中是否存在token
if (!isset($_COOKIE['token'])) {
exit("
<script>
alert('请您先登录');
location.href='login.php';
</script>
");
}
// 2、检测token是否过期
$tokentime = intval(substr($_COOKIE['token'], -10));
if (time() - $tokentime > 60 * 60 * 24 * 7) {
exit("
<script>
alert('登录已过期,请重新登录');
location.href='login.php';
</script>
");
}
// 3、检测token是否非法
$servertoken = $_SESSION['token'];
if ($servertoken != $_COOKIE['token']) {
exit("
<script>
alert('非法令牌,请重新登录');
location.href='login.php';
</script>
");
}
// 4、在session读取用户名id和密码
$id = $_SESSION['id'];
$pwd = $_SESSION['pwd'];
// 5、从数据库中读取用户信息
$salt = 'woxiaoyao';
$pdo = new PDO('mysql:host=localhost;dbname=test', 'root', 'root');
$stmt = $pdo->prepare('SELECT uname,pwd,id FROM user where id = ? and pwd = ?;');
$stmt->execute(array($id, $pwd));
$res = $stmt->fetch(PDO::FETCH_ASSOC);
if ($stmt->rowCount() < 1) {
exit("
<script>
alert('用户不存在,请重新登录或注册');
location.href='login.php';
</script>
");
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>首页</title>
<style>
nav {
height: 40px;
background-color: deepskyblue;
padding: 0 20px;
display: flex;
justify-content: space-between;
align-items: center;
}
nav>a {
color: white;
text-decoration: none;
}
</style>
</head>
<body>
<nav>
<a href="index.php">简书后台管理</a>
<a href="" id="logout">
<span style="color: yellow;"> 欢迎您<?php echo $res['uname']; ?></span> |
退出</a>
</nav>
<script>
document
.querySelector("#logout")
.addEventListener("click", function(ev) {
// 禁用链接跳转行为
ev.preventDefault();
// 询问用户是否退出,并执行对应操作
if (confirm("是否退出?"))
window.location.assign("login.php?action=logout");
});
</script>
</body>
</html>
//login.php
<?php
if (isset($_GET['action']) && $_GET['action'] == 'logout') {
setcookie('token');
session_unset();
session_destroy();
}
?>
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>用户登录</title>
<style>
.container {
width: 30em;
margin: 2em auto;
border-radius: 1em;
background-color: #007d20;
color: white;
padding: 0.2em 0.5em 1em;
text-align: center;
}
form {
display: grid;
grid-template-columns: 5em 1fr;
grid-template-rows: repeat(4, 2em);
place-items: center initial;
gap: 0.5em;
}
form>button {
grid-column: 2/3;
}
form>input[type="checkbox"] {
width: 2em;
height: 2em;
}
</style>
</head>
<body>
<div class="container">
<h3>用户登录</h3>
<form action="check.php" method="post">
<label for="email">用户名:</label>
<input type="text" name="username" id="email" placeholder="输入用户名" required autofocus>
<label for="password">密码:</label>
<input type="password" name="password" id="password" placeholder="密码不少于6位" required>
<label for="autoLogin">自动登录</label>
<input type="checkbox" name="autoLogin" id="autoLogin">
<button>提交</button>
</form>
</div>
</body>
</html>
//check.php
<?php
session_start();
extract($_POST);
// 1、检查是否有用户信息
if (empty($username) || empty($password)) {
exit("
<script>
alert('非法登录');
location.href='login.php';
</script>
");
}
$password = md5($password);
$salt = 'woxiaoyao';
// 2、查询数据库,看用户名和密码是否正确
$pdo = new PDO('mysql:host=localhost;dbname=test', 'root', 'root');
$stmt = $pdo->prepare('SELECT uname,pwd,id FROM user where uname = ? and pwd = ?;');
$stmt->execute(array($username, $password));
$res = $stmt->fetch(PDO::FETCH_ASSOC);
if ($stmt->rowCount() == 1) {
// 3、若勾选了自动登录则记录用户信息
if ($autoLogin == 'on') {
$token = md5($res['id'] . $res['pwd'] . $salt) . time();
setcookie('token', $token, time() + 60 * 60 * 24 * 7);
$_SESSION['token'] = $token;
$_SESSION['id'] = $res['id'];
$_SESSION['pwd'] = $res['pwd'];
} else {
// 4、否则清除cookie和session
setcookie('token');
session_unset();
session_destroy();
}
exit("
<script>
location.href='index.php';
</script>
");
} else {
exit("
<script>
alert('用户名和密码不正确');
location.href='login.php';
</script>
");
}
答:按老师演示MVC自己搭建了框架,模型继承了Medoo,视图继承了Plates,并通过Composer自动加载类,支持嵌套加载,下面截图是目录结构,参考了TP框架的做法
// 核心模型类
<?php
namespace core;
use Medoo\Medoo;
class Model extends Medoo
{
function __construct()
{
$config = [
'database_type' => 'mysql',
'database_name' => 'test',
'server' => 'localhost',
'username' => 'root',
'password' => 'root'
];
parent::__construct($config);
}
}
// 核心视图类
<?php
namespace core;
use League\Plates\Engine;
class View extends Engine{
function __construct($path=null,$fileExtension = 'php')
{
parent::__construct($path,$fileExtension);
}
}
// 用户控制器类
<?php
namespace app\controller;
use PDO;
class User
{
private $model;
private $view;
function __construct($model, $view)
{
$this->model = $model;
$this->view = $view;
}
function index()
{
//分页获取数据
$num = 10;
$sql="select count(id) as total from user";
$res=$this->model->pdo->query($sql)->fetchAll(PDO::FETCH_ASSOC);
$total = intval($res[0]['total']);
$pages = ceil($total / $num);
$page = $_GET['p'] ?? 1;
$offset = ($page - 1) * $num;
$sql="select * from user where true limit {$offset},{$num}";
$users = $this->model->pdo->query($sql)->fetchAll(PDO::FETCH_ASSOC);
// 改进的导航栏
$startPage = 1;
// 显示页码数最好为奇数
$showPage = 5;
if (($page - ceil(($showPage - 1) / 2)) > $startPage)
$startPage = $page - ceil(($showPage - 1) / 2);
return $this->view->render('user/list',["users"=>$users,"pages"=>$pages,"startPage"=>$startPage,"showPage"=>$showPage]);
}
}
// 用户模型类
<?php
namespace app\model;
use core\Model;
class User extends Model
{
}
// 分页模板
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
a {
text-decoration: none;
display: inline-block;
/* width: 2em; */
height: 2em;
line-height: 2em;
}
.container {
width: 60vw;
margin: 1em auto;
}
td {
text-align: center;
}
.page {
margin-top: 1em;
text-align: center;
}
td a:first-child {
margin-right: 5px;
}
td a:last-child {
margin-left: 5px;
}
.page a {
padding: 0 0.5em;
margin: 0 5px;
}
.page a.cur {
background-color: #007d20;
color: white;
}
</style>
<div class="container">
<table border='1' cellspacing="0" width="100%">
<caption>用户信息表</caption>
<thead>
<tr bgColor="lightgray">
<th>ID</th>
<th>name</th>
<th>password</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<?php
foreach ($users as $user) {
$trdata = "<tr>";
foreach ($user as $item) {
$trdata .= "<td>{$item}</td>";
}
$trdata .= "<td><a href='#'>编辑</a><a href='#'>删除</a></td>";
$trdata .= "</tr>";
echo $trdata;
}
?>
</tbody>
</table>
<div class="page">
<?php
echo "<a href='{$_SERVER["PHP_SELF"]}?p=1'>首页</a>";
$prev = ($page - 1 > 1) ? ($page - 1) : 1;
if ($startPage > 1)
echo "<a href='{$_SERVER["PHP_SELF"]}?p={$prev}'>...</a>";
// 加入pages验证,可避免记录数少时出现的错误
for ($i = $startPage; $i < $startPage + $showPage, $i < $pages; $i++) :
if ($i == $page)
echo "<a class='cur' href='{$_SERVER["PHP_SELF"]}?p={$i}'>{$i}</a>";
else
echo "<a href='{$_SERVER["PHP_SELF"]}?p={$i}'>{$i}</a>";
endfor;
$next = ($page + 1) < $pages ? ($page + 1) : $pages;
if ($startPage + $showPage <= $pages + 1)
echo "<a href='{$_SERVER["PHP_SELF"]}?p={$next}'>...</a>";
echo "<a href='{$_SERVER["PHP_SELF"]}?p={$pages}'>未页</a>";
?>
</div>
</div>
// 首页index.php在public目录下
<?php
require_once '../vendor/autoload.php';
use core\Model;
use core\View;
use app\controller\User;
$obj=new User(new Model(),new View('..\app\view'));
echo ($obj->index());