PHP图像字符水印居中

[php]
<?php
//让图像上字符串居中
header("content-type:text/html;charset = utf-8");
//(1)创建画布
$filename = "./images/02.jpg";
$img = imagecreatefromjpeg($filename);
$str = "WELCOME to liuguofeng.com";
$font = 5;
//(2)分配颜色:
$color1 = imagecolorallocate($img,255,0,255);
$color2 = imagecolorallocate($img,255,0,255);
//(3)获取画布宽度和高度
$imgWidth = imagesx($img);
$imgHeight = imagesy($img);
//(4)获取字体尺寸
$fontWidth = imagefontwidth($font);
$fontHeight = imagefontheight($font);
//(5)计算字符串的起始坐标
$x = ($imgWidth-$fontWidth*strlen($str))/2;
$y = ($imgHeight-$fontHeight)/2;
//(6)写入一个字符串
imagestring($img,$font,$x,$y,$str,$color1);
header("content-type:image/jpeg");
imagejpeg($img);
//(7)关闭图像
imagedestroy($img);
?>
[/php]

PHP通过HTTP请求防盗链

anti-theft_chain.php

[php]
<?php
header("content-type:text/html;charset=utf-8");
if(isset($_SERVER['HTTP_REFERER']))
{
//域名对比,一致下载,不一致跳转到错误页面
//strpos: 查找字符串首次出现的位置
if(strpos($_SERVER['HTTP_REFERER'],"https://blog.liuguofeng.com")===0)
{
echo "您可以下载软件了";
}else
{
echo "请从本网站下载";
}
}
?>
[/php]

anti-theft_chain.html

[html]
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>测试页面</title>
</head>
<body>
<a href="https://blog.liuguofeng.com/anti-theft_chain.php">测试页面</p>
</body>
</html>
[/html]

PHP隐藏下载地址

download.php

[php]
<?php
//获取传递的文件名
$filename = $_GET['filename'];
$pathname = "$./download/$filename";
//以只读方式打开文件
$handle = fopen($pathname,"rb");
//返回数据的内容类型
//'octet-stream'八位二进制流
//'content-desposition:attachment'以附件形式打开
header("content-type:application/octet-stream");
header("content-despositon:attachment;filename=$filename");
//循环读取指定大小的内容,并输出
while($str=fread($handle,1024))
{
echo $str;
}
//关闭文件
fclose($handle);
?>
[/php]

download.html

[html]
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<a href="download.php?filename=test.jpg">下载图片</a>
<br>
<a href="download,php?filename=test.mp4">下载视频</a>
</body>
</html>
[/html]

写出5个 PHP 中的魔术方法,并简单描述其作用

__construct();
构造函数:在一个类中定义一个方法作为构造函数。具有构造方法的类在每次创建新对象时先调用此方法,适合在使用对象之前做一些初始化工作
__set();
再给不可访问属性赋值时,__set()会被调用
__get();
读取不可访问属性的值时,__get()会被调用
__isset();
当对不可访问属性调用isset()或empty()时,__isset()会被调用
__unset();
当对不可访问属性调用unset()时,__unset()会被调用

写一个PHP 的抽象类,其中至少还有一个抽象方法,至少含有一个实例方法,并写出其子类

抽象类

PHP 5 支持抽象类和抽象方法。定义为抽象的类不能被实例化。任何一个类,如果它里面至少有一个方法是被声明为抽象的,那么这个类就必须被声明为抽象的。被定义为抽象的方法只是声明了其调用方式(参数),不能定义其具体的功能实现。

继承一个抽象类的时候,子类必须定义父类中的所有抽象方法;另外,这些方法的访问控制必须和父类中一样(或者更为宽松)。例如某个抽象方法被声明为受保护的,那么子类中实现的方法就应该声明为受保护的或者公有的,而不能定义为私有的。此外方法的调用方式必须匹配,即类型和所需参数数量必须一致。例如,子类定义了一个可选参数,而父类抽象方法的声明里没有,则两者的声明并无冲突。 这也适用于 PHP 5.4 起的构造函数。在 PHP 5.4 之前的构造函数声明可以不一样的。

抽象类示例

<?php
abstract class AbstractClass
{
    // 强制要求子类定义这些方法
    abstract protected function getValue();
    abstract protected function prefixValue($prefix);

    // 普通方法(非抽象方法)
    public function printOut() {
        print $this->getValue() . "\n";
    }
}

class ConcreteClass1 extends AbstractClass
{
    protected function getValue() {
        return "ConcreteClass1";
    }

    public function prefixValue($prefix) {
        return "{$prefix}ConcreteClass1";
    }
}

class ConcreteClass2 extends AbstractClass
{
    public function getValue() {
        return "ConcreteClass2";
    }

    public function prefixValue($prefix) {
        return "{$prefix}ConcreteClass2";
    }
}

$class1 = new ConcreteClass1;
$class1->printOut();
echo $class1->prefixValue('FOO_') ."\n";

$class2 = new ConcreteClass2;
$class2->printOut();
echo $class2->prefixValue('FOO_') ."\n";
?>

以上例程会输出:

ConcreteClass1
FOO_ConcreteClass1
ConcreteClass2
FOO_ConcreteClass2

求两个日期的差数

求两个日期的差数,例如2015-2-25,2015-7-22的日期差

<?php
function between ($day1, $day2) {
    if(strtotime($day1) < strtotime($day2)){
        return (strtotime($day2) - strtotime($day1))/86400;
    } else {
        return (strtotime($day1) - strtotime($day2))/86400;
    }
}
echo between ("2015-2-25", "2015-7-22");

输出:147

ThinkPHP 常见面试问题

1.如何理解TP中的单一入口文件?

答:ThinkPHP采用单一入口模式进行项目部署和访问,无论完成什么功能,一个项目都有一个统一(但不一定是唯一)的入口。应该说,所有项目都是从入口文件开始的,并且所有的项目的入口文件是类似的,入口文件中主要包括:
定义框架路径、项目路径和项目名称(可选)
定义调试模式和运行模式的相关常量(可选)
载入框架入口文件(必须)

2.ThinkPHP中的MVC分层是什么?(理解)

MVC 是一种将应用程序的逻辑层和表现层进行分离的方法。ThinkPHP 也是基于MVC设计模式的。MVC只是一个抽象的概念,并没有特别明确的规定,ThinkPHP中的MVC分层大致体现在:
模型(M):模型的定义由Model类来完成。
控制器(C):应用控制器(核心控制器App类)和Action控制器都承担了控制器的角色,Action控制器完成业务过程控制,而应用控制器负责调度控制。
视图(V):由View类和模板文件组成,模板做到了100%分离,可以独立预览和制作。
但实际上,ThinkPHP并不依赖M或者V ,也就是说没有模型或者视图也一样可以工作。甚至也不依赖C,这是因为ThinkPHP在Action之上还有一个总控制器,即App控制器,负责应用的总调度。在没有C的情况下,必然存在视图V,否则就不再是一个完整的应用。
总而言之,ThinkPHP的MVC模式只是提供了一种敏捷开发的手段,而不是拘泥于MVC本身。

3.如何理解 ThinkPHP 3.0 架构(核心 + 行为 + 驱动)中的行为?

答:核心 + 行为 + 驱动   TP官方简称为:CBD
核心(Core):就是框架的核心代码,不可缺少的东西,TP本身是基于MVC思想开发的框架。
行为(Behavior) :行为在新版ThinkPHP的架构里面起着举足轻重的作用,在系统核心之上,设置了很多标签扩展位,而每个标签位置可以依次执行各自的独立行为。行为扩展就因此而诞生了,而且很多系统功能也是通过内置的行为扩展完成的,所有行为扩展都是可替换和增加的,由此形成了底层框架可组装的基础。
驱动( Driver ):数据库驱动、缓存驱动、标签库驱动和模板引擎驱动,以及外置的类扩展。
框架,即framework。其实就是某种应用的半成品,就是一组组件,供你选用完成你自己的系统。简单说就是使用别人搭好的舞台,你来做表演。而且,框架一般是成熟的,不断升级的软件。

4. ThinkPHP如何防止SQL注入?

(1)查询条件尽量使用数组方式,这是更为安全的方式;   (2)如果不得已必须使用字符串查询条件,使用预处理机制;
(3)开启数据字段类型验证,可以对数值数据类型做强制转换;(3.1版本开始已经强制进行字段类型验证了)
(4)使用自动验证和自动完成机制进行针对应用的自定义过滤;
(5)使用字段类型检查、自动验证和自动完成机制等避免恶意数据的输入。

5. 如何开启调试模式?调试模式有什么好处?

开启调试模式很简单,只需要在入口文件中增加一行常量定义代码:

<?php
//开启调试模式
define('APP_DEBUG', true);
//加载框架入口文件
require './ThinkPHP/ThinkPHP.php

在完成开发阶段部署到生产环境后,只需要删除调试模式定义代码即可切换到部署模式。开启调试模式后,系统会首先加载系统默认的调试配置文件,然后加载项目的调试配置文件,调试模式的优势在于:
开启日志记录,任何错误信息和调试信息都会详细记录,便于调试;
关闭模板缓存,模板修改可以即时生效;
记录SQL日志,方便分析SQL;
关闭字段缓存,数据表字段修改不受缓存影响;
严格检查文件大小写(即使是Windows平台),帮助你提前发现Linux部署问题;
可以方便用于开发过程的不同阶段,包括开发、测试和演示等任何需要的情况,不同的应用模式可以配置独立的项目配置文件。

6. TP中支持哪些配置模式?优先级?

ThinkPHP在项目配置上面创造了自己独有的分层配置模式,其配置层次体现在:

惯例配置->项目配置->调试配置->分组配置->扩展配置->动态配置

以上是配置文件的加载顺序,因为后面的配置会覆盖之前的同名配置(在没有生效的前提下),所以优先顺序从右到左。

7. TP中的URL模式有哪几种?默认是哪种?

ThinkPHP支持四种URL模式,可以通过设置URL_MODEL参数来定义,包括普通模式、PATHINFO、REWRITE和兼容模式。
默认模式为:PATHINFO模式,设置URL_MODEL 为1

8. TP中系统变量有哪些?如何获取系统变量?

获取系统变量的方法: 只需要在Action中调用下面方法: $this->方法名("变量名",["过滤方法"],["默认值"])

9、ThinkPHP框架中D函数与M函数的区别是什么?

答:M方法实例化模型无需用户为每个数据表定义模型类,D方法可以自动检测模型类,如果存在自定义的模型类,则实例化自定义模型类,如果不存在,则会自动调用M方法去实例化Model基类。同时对于已实例化过的模型,不会重复去实例化(单例模式)。