通过
Response
类,设置合适的
content
和
headers
,即可创建任何类型的响应。一个JSON响应看起来像下面这样:
use Symfony\Component\HttpFoundation\Response;
$response = new Response();
$response->setContent(json_encode(array(
'data' => 123,
$response->headers->set('Content-Type', 'application/json');
use Symfony\Component\HttpFoundation\JsonResponse;
$response = new JsonResponse();
$response->setData(array(
'data' => 123
这可以把你的data数组转换成JSON,然后设置其Content-Type头为application/json。
对于任何应用程序来说,一个最常见和最具挑战的任务,就是从数据库中读取和持久化数据信息。尽管symfony框架并未整合任何需要使用数据库的组件,但是却紧密集成了一个名为 Doctrine 的三方类库。Doctrine的主要目标是为你提供一个强有力的工具,令数据库互动更加轻松和灵活。
配置数据库
(略):各个框架集成的database_config各不相同,自己配置就好
创建一个Entity类
假设你正构建一套程序,其中有些产品需要展示。即使不考虑Doctrine或者数据库,你也已经知道你需要一个Product对象来呈现这些产品。在你AppBundle的Entity目录下创建这个类:
// src/AppBundle/Entity/Product.php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
* @ORM\Entity
* @ORM\Table(name="product")
class Product
* @ORM\Column(type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
private $id;
* @ORM\Column(type="string", length=100)
private $name;
* @ORM\Column(type="decimal", scale=2)
private $price;
* @ORM\Column(type="text")
private $description;
即是建表一样,设置好每个字段的格式,长度。考验你SQL基础的时候
创建数据表/Schema
现在你有了一个包含映射信息的可用Product类,因此Doctrine确切地知道如何持久化它。当然,你还没有相应的Product数据表在库中。幸运的是,Doctrine可以自动创建所有的数据表。要这么做,运行以下命令:
php bin/console doctrine:schema:update --force
它会比较你的数据库 理论上应该是 什么样子的(基于你的entities的映射信息)以及 实际上 它应该是什么样,然后执行所需的SQl语句来将数据库的schema 更新到 它所应有的样子。换句话说,如果你添加了一个包含“映射元数据”(mapping metadata)的新属性到Product并运行此任务,它将执行所需的 “ALTER TABLE” 语句,向已经存在的Product表添加那个新列。
// src/AppBundle/Controller/HelloController.php
// ...
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
* @Route("/hello/{name}", name="hello")
public function indexAction($name)
// ...
控制器有个参数$name,对应所匹配路由的{name}参数(如果你访问/hello/ryan, 在本例中是ryan)。实际上当执行你的控制器时,Symfony在所匹配路由中匹配带参数控制器中的每个参数。所以这个{name}值被传入到$name。只需要确保占位符的名称和参数名称一样就行。
以下是更有趣的例子,这里的控制器有两个参数:
* @Route("/hello/{firstName}/{lastName}", name="hello")
public function indexAction($firstName, $lastName)
// ...
将路由参数映射到控制器参数是十分容易和灵活的。在你开发时请遵循以下思路:
1. 控制器参数的顺序无关紧要
Symfony可以根据路由参数名匹配控制器方法参数。换句话说,它可以实现last_name参数与$last_name参数的匹配。控制器可以在随意排列参数的情况下正常工作。
public function indexAction($lastName, $firstName)
// ...
2.控制器所需参数必须匹配路由参数
下面会抛出一个运行时异常(RuntimeException),因为在路由定义中没有foo
参数:
public function indexAction($firstName, $lastName, $foo)
// ...
如果参数是可选的,那该多好。下面的例子不会抛出异常:
public function indexAction($firstName, $lastName, $foo = 'bar')
// ...
3.不是所有的路由参数都需要在控制器上有响应参数的
如果,举个例子,last_name对你控制器不是很重要的话,你可以完全忽略掉它:
public function indexAction($firstName)
// ...
我们的新控制器返回一个简单的HTML页。为了能够在指定的URI中渲染该控制器,我们需要为它创建一个路由。 我们将在路由章节中讨论路由组件的细节,但现在我们为我们的控制器创建一个简单路由:
// src/AppBundle/Controller/HelloController.php
namespace AppBundle\Controller;
use Symfony\Component\HttpFoundation\Response;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
class HelloController
* @Route("/hello/{name}", name="hello")
public function indexAction($name)
return new Response('<html><body>Hello '.$name.'!</body></html>');
现在,你来到/hello/ryan(例如,如果你使用内置的web服务http://localhost:8000/hello/ryan
),那么它就会执行HelloController::indexAction()
控制器,并且将ryan赋给$name变量。创建这样一个页面就能够让路由跟控制器做简单的关联
创建一个命令
命令通过类来定义,这些类必须存放在你的bundle (如 AppBundle\Command) 的 Command 命名空间下。类名必须是 Command 后缀。
例如,一个名为 CreateUser 的命令必须遵循此结构:
// src/AppBundle/Command/CreateUserCommand.php
namespace AppBundle\Command;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
class CreateUserCommand extends Command
protected function configure()
// ...
protected function execute(InputInterface $input, OutputInterface $output)
// ...
首先,你必须在configure()方法中配置命令的名称。然后可选地定义一个帮助信息(help message)和 输入选项及输入参数(input options and arguments):
// ...
protected function configure()
$this
// the name of the command (the part after "bin/console")
// 命令的名字("bin/console" 后面的部分)
->setName('app:create-users')
// the short description shown while running "php bin/console list"
// 运行 "php bin/console list" 时的简短描述
->setDescription('Creates new users.')
// the full command description shown when running the command with
// the "--help" option
// 运行命令时使用 "--help" 选项时的完整命令描述
->setHelp("This command allows you to create users...")
配置命令之后,你就能在终端(terminal)中执行它:
php bin/console app:create-users
你可能已经预期,这个命令将什么也不做,因为你还没有写入任何逻辑。在execute()方法里添加你自己的逻辑,这个方法可以访问到input stream(如,选项和参数)和output stream(以写入信息到命令行):
// ...
protected function execute(InputInterface $input, OutputInterface $output)
// outputs multiple lines to the console (adding "\n" at the end of each line)
// 输出多行到控制台(在每一行的末尾添加 "\n")
$output->writeln([
'User Creator',
'============',
// outputs a message followed by a "\n"
$output->writeln('Whoa!');
// outputs a message without adding a "\n" at the end of the line
$output->write('You are about to ');
$output->write('create a user.');
现在,尝试执行此命令:
tp官方使用的批量加载需要固定常量,或者固定的某个或多个变量,例:
{include file="$html_a,$html_b" /}
{include file="/view/book/a.html,/view/book/a.html" /}
tp官方代码中,标签解析函数(\thinkphp\library\think\Template.php):
* 分析加载的模板文件并读取内容 支持多个模板文件读取
* @access private
* @param string $templateName 模板文件名
* @return string
private function parseTemplateName($templateName)
$array = explode(',', $templateName);
$parseStr = '';
foreach ($array as $templateName) {
if (empty($templateName)) {
continue;
if (0 === strpos($templateName, '$')) {
//支持加载变量文件名
$templateName = $this->get(substr($templateName, 1));
$template = $this->parseTemplateFile($templateName);
if ($template) {
// 获取模板文件内容
$parseStr .= file_get_contents($template);
return $parseStr;
我们可以看到,官方函数中,先把多个参数解释成数组再进行下一步加载。即使加入了变量参数,仍导致我们要事先确立好需要加载的文件数量。
* 分析加载的模板文件并读取内容 支持多个模板文件读取
* @access private
* @param string $templateName 模板文件名
* @return string
private function parseTemplateName($templateName)
if (0 === strpos($templateName, '$')) {
//支持加载变量文件名
$templateName = $this->get(substr($templateName, 1));
$array = explode(',', $templateName);
$parseStr = '';
foreach ($array as $templateName) {
if (empty($templateName)) {
continue;
$template = $this->parseTemplateFile($templateName);
if ($template) {
// 获取模板文件内容
$parseStr .= file_get_contents($template);
return $parseStr;
把官方的自带变量识辨解析函数提前到循环外解析,这样你可在控制器中自定义你所需要加载的文件数量以及各自的文件路径。
最后,官方的模板解析函数传递的变量无法太过复杂,控制器事先把数组转换成排列字符串即可。
if ($file = request()->file('fileUpload')) {
// 移动到框架应用根目录/public/uploads/ 目录下 move("保存地址","保存名称")
$info = $file->validate(['ext' => 'xls'])->move(ROOT_PATH . 'public' . DS . 'uploads', date('YmdHis'));
if ($info) {
//加载PHPExcel类,解析表格,结果为二维数组
import('PHPExcel.Classes.PHPExcel', '', '.php');
$object = new \PHPExcel_Reader_Excel5();
// $file_name = '/public/uploads/' . $file_name;
// $file_name = iconv("utf-8", "gb2312",$file_name);
$objPHPExcel = $object->load($info->getPathname());
$ExcelData = $objPHPExcel->getActiveSheet()->toArray('', true, true, true);
//验证Excel第2行($ExcelData[2])非空列数
// if (count(array_filter($ExcelData[2])) != 8)
// $this->error('订单字段不正确,请参照模板');
//输出实例
print_r('<pre>');
print_r($ExcelData);
} else {
// 上传失败获取错误信息
$this->error($file->getError());
}else{
return '<body><form action="" method="post" enctype="multipart/form-data"><input type="file" name="fileUpload" /><input type="submit" value="上传Excel文件" /></form></body>';
PHPExcel导出(Excel5)
* 乘法口诀表
* @return mixed
public function index()
$objPHPExcel = new \PHPExcel();
$row_array = [1, 2, 3, 4, 5, 6, 7, 8, 9];
$column_array = ['one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine'];
$column = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', "I", 'J'];
* setCellValue(列ABC . 行123, "字段")
* 注意垃圾Excel从1开始数
$objPHPExcel->getActiveSheet()->setCellValue($column[0] . '1', "\\");
foreach ($column_array as $key=>$value) {
$objPHPExcel->getActiveSheet()->setCellValue($column[$key+1] . '1', $value);
$row = 2; //第二行开始
foreach ($row_array as $number) { //每行
$objPHPExcel->getActiveSheet()->setCellValue('A' . $row, $number);
foreach ($column_array as $key => $value) { //这一行的每列,第二列开始
$objPHPExcel->getActiveSheet()->setCellValue($column[$key+1] . $row, ($key+1) * $number);
$row++; //下一行
// 输出Excel表格到浏览器下载
ob_end_clean();
header('Content-Type: application/vnd.ms-excel');
header('Content-Disposition: attachment;filename="abc.xls"');
header('Cache-Control: max-age=0');
// If you're serving to IE 9, then the following may be needed
header('Cache-Control: max-age=1');
// If you're serving to IE over SSL, then the following may be needed
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); // Date in the past
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT'); // always modified
header('Cache-Control: cache, must-revalidate'); // HTTP/1.1
header('Pragma: public'); // HTTP/1.0
$objIOFactory = \PHPExcel_IOFactory::createWriter($objPHPExcel, 'Excel5');
return $objIOFactory->save('php://output');
出于版权保护的考虑,如果在Word 2010中打开从网络上下载的文档,Word 2010会自动处于保护模式下,默认禁止编辑,想修改必须点击一下启用编辑(Enble Editing)。
原因分析:由于office 2010的一些新功能造成了这种情况。
临时解决办法:修改文件属性
选择需要打开的文件,点右键属性里面选择”解除锁定”,然后确定后。即可正常打开了。
彻底解决办法:修改选项配置
进入文件菜单中的选项->信任中心->点信任中心设置然后点受保护的视图,把右边的所有钩上的内容都不钩,最后保存退出即可。
Word/Excel都要设置一下。
$vCity = [
'11', '12', '13', '14', '15', '21', '22',
'23', '31', '32', '33', '34', '35', '36',
'37', '41', '42', '43', '44', '45', '46',
'50', '51', '52', '53', '54', '61', '62',
'63', '64', '65', '71', '81', '82', '91',
if (!preg_match('/^([\d]{17}[xX\d]|[\d]{15})$/', $vStr))
return false;
if (!in_array(substr($vStr, 0, 2), $vCity))
return false;
$vStr = preg_replace('/[xX]$/i', 'a', $vStr);
$vLength = strlen($vStr);
if ($vLength == 18) {
$vBirthday = substr($vStr, 6, 4) . '-' . substr($vStr, 10, 2) . '-' . substr($vStr, 12, 2);
} else {
$vBirthday = '19' . substr($vStr, 6, 2) . '-' . substr($vStr, 8, 2) . '-' . substr($vStr, 10, 2);
if (date('Y-m-d', strtotime($vBirthday)) != $vBirthday)
return false;
if ($vLength == 18) {
$vSum = 0;
for ($i = 17; $i >= 0; $i--) {
$vSubStr = substr($vStr, 17 - $i, 1);
$vSum += (pow(2, $i) % 11) * (($vSubStr == 'a') ? 10 : intval($vSubStr, 11));
if ($vSum % 11 != 1)
return false;
return true;