PHP7+TP3.2.3 使用记录


一、REWRITE模式开启

1.更改 Apache httpd.conf 配置文件

1.1、加载 mod_rewrite.so,确认加载了 mod_rewrite.so 模块(将如下配置前的 # 号去掉):

1.2、更改 AllowOverride 配置,如果tp3目录在www下的/tp3,直接在httpd.conf底部添加下面代码:

 
	AllowOverride All 
 
1.3、添加 .htaccess 文件(TP3主目录下就有,确保代码没错和在入口文件同级目录就ok)



RewriteEngine on

RewriteCond %{REQUEST_FILENAME} !-d

RewriteCond %{REQUEST_FILENAME} !-f

RewriteRule ^(.*)$ index.php/$1 [QSA,PT,L]

2.更改TP3项目配置文件

2.1、编辑项目配置文件 Conf/config.php ,将 URL 模式配置为 2(Rewrite模式):

'URL_MODEL' => 2,


OK,重启Apache,就可以 http://localhost/tp3/home/index/index 访问了


二、Oracle的连接

2.1、更改模块配置或者项目配置的config.php

'配置值'
    'DB_TYPE'            => 'oracle', // 数据库类型
    'DB_USER'            => 'user', // 用户名
    'DB_PWD'             => 'pwd', // 密码
    'DB_PREFIX'          => '', // 数据库表前缀
    'DB_DSN'             => 'oci:host=127.0.0.1;dbname=TestOrcl;charset=utf8'
);

2.2、实际使用,详细查看TP3.2.3开发手册

      // 实例化Member对象
        $db = M('Member');

        //数据更新
//       方法1:
//        $db->realname = 'ThinkPHP2';
//          $count = $db->where('id=1')->save();

//        方法2:
//        $data['realname']='ThinkPhP';
//        $count=$db->where('id=1')->save($data);
//        if($count==1){
//            echo '';
//        }


//        写入
        //下一个自增ID
//        $id = $db->getNextInsID('member_seq');
//        $data['id'] = $id;//字段必须要小写,不然会忽略掉
//        $data['loginname'] = '13800138000';
//        $data['realname'] = 'tp3';
//        $data['password'] = '123456';
//        $count = $db->add($data);
//
//        $str="alert('add ".($count?"sussecc!":"fail!")."')";
//        echo '';

//        删除
//        $count=$db->where('id>=865 and id<=902')->delete();
//        $str="alert('del ".($count?"sussecc!":"fail!")."')";
//        echo '';


//      查询
        $result = $db->field('id,LoginName,RealName,to_char(LASTACTTIME, \'YYYY-MM-DD HH24:MI:SS\') as LASTACTTIME')->where('id<10')->order('id')->limit(10)->select();
        dump($result);

        //SQL查询
        //$Model = new \Think\Model();
        //$result=$Model->query("select * from member t1 left join zy t2 on t2.memberid=t1.id  where t2.id is not null");
        //dump($result);

2.3、添加自增ID方法,修改ThinkPHP/Library/Think/Db/Driver/Oracle.class.php文件

/**
     * TODO
     * 2016-05-09 新增方法 修复bug 修复及支持获取自增Id的上次记录 by czw
     * 取得Oracle最近插入的ID
     * @access public
     */
    public function getNextInsID($sequence = '') {
        try {
            $lastInsID = $this->_linkID->lastInsertId();
        } catch(\PDOException $e) {
            //对于驱动不支持PDO::lastInsertId()的情况
            try {
                $lastInsID = 0;
                $seqPrefix = C("DB_SEQUENCE_PREFIX") ? C("DB_SEQUENCE_PREFIX") : 'seq_';
                $seqSuffix = C("DB_SEQUENCE_SUFFIX") ? C("DB_SEQUENCE_SUFFIX") : '';
                $sequence = strtoupper($sequence ? $sequence : $seqPrefix.$this->table.$seqSuffix);
                $q = $this->query("SELECT {$sequence}.nextval  as t FROM DUAL");
                if($q) {
                    $lastInsID = $q[0]['t'];
                }
            } catch(\Exception $e) {
                print "Error!: " . $e->getMessage() . "
"; exit; } } return $lastInsID; }

2.4、把上述文件中的execute()方法中,查询sequence的代码和执行$this->PDOStatement->execute();失败后,获取主键字段自动调用获取自增的代码删除掉!多次测试发现在调试模式下,发起插入数据的操作时,缺少主键数据不会返回false从而执行后边的获取自增部分代码。直接报错,干脆剔掉吧。自己直接单独提前获取好主键自增ID后,再提交执行。

 /**
     * 执行语句
     * @access public
     * @param string $str  sql指令
     * @param boolean $fetchSql  不执行只是获取SQL
     * @return integer
     */
    public function execute($str,$fetchSql=false) {
        $bind = $this->bind; //TODO 新增 修复bug 修复及支持获取自增Id的上次记录 by czw
        $this->initConnect(true);
        if ( !$this->_linkID ) return false;
        $this->queryStr = $str;
        if(!empty($this->bind)){
            $that   =   $this;
            $this->queryStr =   strtr($this->queryStr,array_map(function($val) use($that){ return '\''.$that->escapeString($val).'\''; },$this->bind));
        }
        if($fetchSql){
            return $this->queryStr;
        }

        //释放前次的查询结果
        if ( !empty($this->PDOStatement) ) $this->free();
        $this->executeTimes++;
        N('db_write',1); // 兼容代码
        // 记录开始执行时间
        $this->debug(true);
        $this->PDOStatement    =    $this->_linkID->prepare($str);
        if(false === $this->PDOStatement) {
            $this->error();
            return false;
        }
        $this->bind = $this->bind ? $this->bind : $bind;//TODO 新增 修复bug 修复及支持获取自增Id的上次记录 by czw
        foreach ($this->bind as $key => $val) {
            if(is_array($val)){
                $this->PDOStatement->bindValue($key, $val[0], $val[1]);
            }else{
                $this->PDOStatement->bindValue($key, $val);
            }
        }
        $this->bind =   array();
        $result    =    $this->PDOStatement->execute();
        $this->debug(false);
        if ( false === $result) {
            $this->error();
        }
        return $result;
    }

2.5、把ThinkPHP/Library/Think/Model.class.php文件中的getLastInsID()方法改成:

  /**
     * 返回最后插入的ID
     * @access public
     * @return string
     */
    public function getNextInsID($sequence) {
        return $this->db->getNextInsID($sequence);
    }
以后直接可以通过下面方法获取下一自增ID

$id = $db->getNextInsID('member_seq');


三、图片上传

3.1、打开ThinkPHP\Library\Think\Upload\Driver\Local.class.php, 找到checkRootPath()方法修改rootPath变量

public function checkRootPath($rootpath){
        if(!(is_dir('./') && is_writable('./'))){
            $this->error = '上传根目录不存在!请尝试手动创建:'.$rootpath;
            return false;
        }
        $this->rootPath = $rootpath;
        return true;
    }

3.2、在控制层新建一个操作方法upload()

 $upload = new \Think\Upload();// 实例化上传类
        $upload->maxSize = 1 * 1024 * 1024;// 设置附件上传大小,1024*1024为1MB
        $upload->exts = array('jpg', 'gif', 'png', 'jpeg');// 设置附件上传类型
        $upload->rootPath = 'Public/'; // 设置附件上传根目录
        $upload->savePath = 'Uploads/'; // 设置附件上传(子)目录

        //是否使用子目录保存上传文件
        $upload->autoSub = true;
        // 采用date函数生成命名规则 传入Y-m-d参数
        $upload->saveName = array('udate',array('YmdHisu'));
        // 上传文件
        $info = $upload->upload();
        $data = null;
        if (!$info) {// 上传错误提示错误信息
            $data = [
                'Status' => 'Err',
                'Content' => $upload->getError()
            ];
        } else {// 上传成功
            $data = [
                'Status' => 'OK',
                'Content' => '上传成功'
            ];
        }
        print_r(json_encode($data));
$upload->saveName = array('udate',array('YmdHisu'));

在\tp3\ThinkPHP\Common\functions.php文件下新建一个可以获取毫秒级时间的字符串方法,用作命名上传文件。

/**
 * 获取毫秒级的时间字符串
 * @param string $format 日期格式:默认u只返回毫秒,‘Y-m-d H:i:s.u’详细
 * @return string
 */
function udate($format = 'u', $utimestamp = null) {
    if (is_null($utimestamp))
        $utimestamp = microtime(true);

    $timestamp = floor($utimestamp);
    $milliseconds = round(($utimestamp - $timestamp) * 1000000);

    return date(preg_replace('`(?

3.3、在View下新建一个HTML文件




    
    php图片上传测试



详细直接参考: http://document.thinkphp.cn/manual_3_2.html#upload

待续

三、图片上传

3.1、打开ThinkPHP\Library\Think\Upload\Driver\Local.class.php, 找到checkRootPath()方法修改rootPath变量

public function checkRootPath($rootpath){
        if(!(is_dir('./') && is_writable('./'))){
            $this->error = '上传根目录不存在!请尝试手动创建:'.$rootpath;
            return false;
        }
        $this->rootPath = $rootpath;
        return true;
    }

3.2、在控制器新建一个操作方法upload()

$config = array(
            'maxSize'    =>    1 * 1024 * 1024,     // 设置附件上传大小,1024*1024为1MB
            'rootPath'   =>    'Public/',           // 设置附件上传根目录
            'savePath'   =>    'Uploads/',          // 设置附件上传(子)目录
            //'saveName'   =>    array('uniqid',''),  //默认采用uniqid函数生成一个唯一的字符串序列。
            'saveName'   =>   array('udate', array('YmdHisu')),  // 采用自定义udate函数生成命名规则 传入YmdHisu参数
            'exts'       =>    array('jpg', 'gif', 'png', 'jpeg'),// 设置附件上传类型
            'autoSub'    =>    true,                //是否使用子目录保存上传文件
            'subName'    =>    array('date','Ymd'), //子目录命名规则
            //'subName'    =>   'get_user_id',         //可以使用自定义函数来保存,和saveName参数一样
        );

        $upload = new \Think\Upload($config);   // 实例化上传类

        // 上传所有文件
        //$info = $upload->upload();

        // 上传单个文件,current($_FILES)获取$_FILES数组第一个值
        $info = $upload->uploadOne(current($_FILES));

        $data = null;
        if (!$info) {// 上传错误提示错误信息
            $data = [
                'Status' => 'Err',
                'Content' => $upload->getError()
            ];
        } else {// 上传成功
            $data = [
                'Status' => 'OK',
                'Content' => '上传成功'
            ];
        }
        print_r(json_encode($data));

$upload->saveName = array('udate',array('YmdHisu'));

在\tp3\ThinkPHP\Common\functions.php文件下新建一个可以获取毫秒级时间的字符串方法,用作命名上传文件。

/**
 * 获取毫秒级的时间字符串
 * @param string $format 日期格式:默认u只返回毫秒,‘Y-m-d H:i:s.u’详细
 * @return string
 */
function udate($format = 'u', $utimestamp = null) {
    if (is_null($utimestamp))
        $utimestamp = microtime(true);

    $timestamp = floor($utimestamp);
    $milliseconds = round(($utimestamp - $timestamp) * 1000000);

    return date(preg_replace('`(?

3.3、在View下新建一个HTML文件




    
    php图片上传测试



ps:在本地测试多文件上传时,注意文件命名规则会否在毫秒级产生相同命名,导致覆盖操作,误以为多文件上传错误。

详细直接参考: http://document.thinkphp.cn/manual_3_2.html#upload


四、命名范围功能

要使用命名范围功能,主要涉及到模型类的_scope属性定义和scope连贯操作方法的使用。

Home模块Model下新建模型类MemberModel.class.php(文件名,注意不能少了.class)

protected $_scope = array(
        // 命名范围normal
        'normal' => array(
            'where' => array('State' => 1)
        ),
        // 命名范围latest
        'latest' => array(
            'order' => 'LastActTime	DESC',
            'limit' => 10
        )
    );
调用:

$Model  = D('Member');// 这里必须使用D方法 因为命名范围在模型里面定义
        $result = $Model->scope('normal,latest')->select();
        dump($result);


五、字段映射

5.1、ThinkPHP的字段映射功能可以让你在表单中隐藏真正的数据表字段,而不用担心放弃自动创建表单对象的功能,假设我们的User表里面有username和email字段,我们需要映射成另外的字段,定义方式如下:

'loginname',// 把表单中mobile映射到数据表的loginname字段
        'name'  =>'realname'
    );

5.2、在设置开启 READ_DATA_MAP参数

    'READ_DATA_MAP'=>true, //读取数据根据模型字段映射返回

六、PHPExcel操作

1、下载地址:http://phpexcel.codeplex.com/  ps:当前使用thinkphp3.2.3,请下载1.7.9版本。亲测1.8.0版本在TP3.23下,调用报....PHPEXCEL not found...,本人初学愚钝据网上各种方法进行N次处理还是解决不了。后来降到1.79后,一切顺利

2、把下载文件中的PHPExcel目录和PHPExcel.php放到TP框架 \ThinkPHP\Library\Org\Util\下

3、因为PHPExcel没有用命名空间,只能inport导入

4、自己写的读取、导出excel通用方法,有详细注释。基本看懂了就够用了。也可以百度 ‘PHPExcel中文开发手册’,看下详细参数设置使用说明。

/**
 * 导出正规数据excel表
 * @param string $fileName 标题
 * @param array $headArr 列头\字段\宽度和定义
 * $headArr = array(
 *    'id' => ['text' => '用户ID', 'width' => 10],
 *   'name' => ['text' => '用户名字', 'width' => 20]
 * );
 * @param array $data 数据源
 * @return boolean
 */
function getExcel($fileName, $headArr, $data)
{
    //对数据进行检验
    if (empty($data) || !is_array($data)) {
        die("数据源错误");
    }
    //检查文件名
    if (empty($fileName)) {
        exit;
    }

    //导入PHPExcel类库,因为PHPExcel没有用命名空间,只能inport导入
    import("Org.Util.PHPExcel");
    import("Org.Util.PHPExcel.Writer.Excel5");
    import("Org.Util.PHPExcel.IOFactory.php");

    //创建PHPExcel对象,注意,不能少了\
    $objPHPExcel = new \PHPExcel();
    $objProps = $objPHPExcel->getProperties();

    $objProps->setCreator('Nicky');//创建人
    $objProps->setLastModifiedBy('Nicky');//最后修改人
    $objPHPExcel->setActiveSheetIndex(0);//设置当前的sheet
    $objActSheet = $objPHPExcel->getActiveSheet(); //获取当前sheet
    $objActSheet->setTitle($fileName);  //当值sheet标题

    //边框样式
    $styleArray = array(
        'borders' => array(
            'allborders' => array(
                //'style' => PHPExcel_Style_Border::BORDER_THICK,//边框是粗的
                'style' => \PHPExcel_Style_Border::BORDER_THIN,//细边框
                //'color' => array('argb' => 'FFFF0000'),
            ),
        ),
    );
    //所有单元格水平居中、垂直居中
    $objPHPExcel->getDefaultStyle()->getAlignment()->setHorizontal(\PHPExcel_Style_Alignment::HORIZONTAL_CENTER);
    $objPHPExcel->getDefaultStyle()->getAlignment()->setVertical(\PHPExcel_Style_Alignment::VERTICAL_CENTER);
    //所有单元格行高
    $objActSheet->getDefaultRowDimension()->setRowHeight(20);
    //字体
    $objPHPExcel->getDefaultStyle()->getFont()->setName('宋体');

    //************************** 设置列头标题 ***********************
    $key = ord("A");
    foreach ($headArr as $v) {
        $colum = chr($key);
        $objActSheet->setCellValue($colum . '2', $v['text']);
        if (empty($v['width'])) {
            $objActSheet->getColumnDimension($colum)->setAutoSize(true);
        } else {
            $objActSheet->getColumnDimension($colum)->setWidth($v['width']);
        }
        $key += 1;
    }

    //列数
    $tmp = chr($key - 1);

    //************************** end ***********************


    //************************** 设置第一行大标题 ***********************
    $objActSheet->setCellValue('A1', $fileName);
    $objActSheet->getRowDimension('1')->setRowHeight(30);
    $objActSheet->getStyle('A1')->getFont()->setSize(23);

    $objActSheet->mergeCells('A1:' . $tmp . '1');//合并单元格

    //************************** end ***********************

    $column = 3;
    //写入数据
    foreach ($data as $key => $rows) {// 行写入
        $span = ord("A");
        foreach ($headArr as $k => $v) {
            $j = chr($span);
            $objActSheet->setCellValue($j . $column, $rows[$k]);
            $span++;
        }
        $column++;
    }

    //设置列头填充颜色
    $objActSheet->getStyle('A2:' . $tmp . '2')->getFill()->setFillType(\PHPExcel_Style_Fill::FILL_SOLID);
    $objActSheet->getStyle('A2:' . $tmp . '2')->getFill()->getStartColor()->setARGB('FF1494DF');

    //设置列头和标题字体加粗
    $objActSheet->getStyle('A1:' . $tmp . '2')->getFont()->setBold(true);
    //设置全局边框
    $objActSheet->getStyle('A1:' . $tmp . ($column - 1))->applyFromArray($styleArray);//这里就是画出从单元格A5到N5的边框,看单元格最右边在哪哪个格就把这个N

    $date = date("Y_m_d", time());
    $fileName .= "_{$date}.xls";
    $fileName = iconv("utf-8", "gb2312", $fileName);

    ob_end_clean();//清除缓冲区,避免乱码
    header('Content-Type: application/vnd.ms-excel');
    header("Content-Disposition: attachment;filename=\"$fileName\"");
    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');

    $objWriter = \PHPExcel_IOFactory::createWriter($objPHPExcel, 'Excel5');
    $objWriter->save('php://output'); //文件通过浏览器下载
    exit;
}

/**
 * 读取Excel数据
 * @param string $path 文件路径(ps:./Public/1.xls)
 * @param int $beginRow 开始行数
 * @return array $arr 读取出来的数据
 */
function readExcel($path, $beginRow = 1)
{
    //导入PHPExcel类库,因为PHPExcel没有用命名空间,只能inport导入
    import("Org.Util.PHPExcel");
    //创建PHPExcel对象,注意,不能少了\
//    $PHPExcel=new \PHPExcel();
    //如果excel文件后缀名为.xls,导入这个类
    import("Org.Util.PHPExcel.Reader.Excel5");
    $PHPReader = new \PHPExcel_Reader_Excel5();

    //如果excel文件后缀名为.xlsx,导入这下类
    //import("Org.Util.PHPExcel.Reader.Excel2007");
    //$PHPReader=new \PHPExcel_Reader_Excel2007();

    //载入文件
    $PHPExcel = $PHPReader->load($path);
    //获取表中的第一个工作表,如果要获取第二个,把0改为1,依次类推
    $currentSheet = $PHPExcel->getSheet(0);
    //获取总列数
    $allColumn = $currentSheet->getHighestColumn();
    //获取总行数
    $allRow = $currentSheet->getHighestRow();
    //循环获取表中的数据,$currentRow表示当前行,从哪行开始读取数据,索引值从0开始
    for ($currentRow = $beginRow; $currentRow <= $allRow; $currentRow++) {
        //从哪列开始,A表示第一列
        for ($currentColumn = 'A'; $currentColumn <= $allColumn; $currentColumn++) {
            //数据坐标
            $address = $currentColumn . $currentRow;
            //读取到的数据,保存到数组$arr中
            $arr[$currentRow - $beginRow][$currentColumn] = $currentSheet->getCell($address)->getValue();
        }
    }
    return $arr;
}

挂一个完整参考资源代码 下载


七、IP定位扩展类库 使用

1.查找项目\ThinkPHP\Library\Org\Net\,是否存在IpLocation.class.php文件。没有去官网扩展下载后放在该路径下

2.下载IP地址库文件,官网扩展下载(UTF版) 或 纯真下载最新 (GBK版) 

3.默认加载路径是IpLocation.class.php同目录下的UTFWry.dat,把下载的地址库dat文件放到路径下,然后改路径或文件名。确保路径没错就ok

4.如果是GBK版本的地址库要转码,修改IpLocation.class.php的getlocation()方法 最后返回
return iconv('gbk','utf-8',$location['country'].$location['area']);;

5.控制器操作调用
//测试
    public function test(){
        $tmp=new \Org\Net\IpLocation();//导入IpLocation类
        dump($tmp->getlocation('8.8.8.8'));
    }


八、发起http请求


1.一个常用的通过cURL发送HTTP请求的函数,可以添加到Common/function.php里面

/**
 * 发送HTTP请求方法
 * @param  string $url 请求URL
 * @param  array $params 请求参数
 * @param  string $method 请求方法GET/POST
 * @param array $header
 * @param bool $multi
 * @return array $data   响应数据
 * @throws Exception
 */
function http($url, $params, $method = 'GET', $header = array(), $multi = false){
    $opts = array(
        CURLOPT_TIMEOUT        => 30,
        CURLOPT_RETURNTRANSFER => 1,
        CURLOPT_SSL_VERIFYPEER => false,
        CURLOPT_SSL_VERIFYHOST => false,
//        CURLOPT_DNS_USE_GLOBAL_CACHE => false,
//        CURLOPT_DNS_CACHE_TIMEOUT => 2,
        CURLOPT_HTTPHEADER     => $header
    );

    /* 根据请求类型设置特定参数 */
    switch(strtoupper($method)){
        case 'GET':
            $opts[CURLOPT_URL] = $url . '?' . http_build_query($params);
            break;
        case 'POST':
            //判断是否传输文件
            $params = $multi ? $params : http_build_query($params);
            $opts[CURLOPT_URL] = $url;
            $opts[CURLOPT_POST] = 1;
            $opts[CURLOPT_POSTFIELDS] = $params;
            break;
        default:
            throw new Exception('不支持的请求方式!');
    }

    /* 初始化并执行curl请求 */
    $ch = curl_init();
    curl_setopt_array($ch, $opts);
    $data  = curl_exec($ch);
    $error = curl_error($ch);
    curl_close($ch);
    if($error) throw new Exception('请求发生错误:' . $error);
    return  $data;
}


2. 打开php.ini,开启extension=php_curl.dll

3.检查php.ini的extension_dir值是哪个目录,检查有无php_curl.dll,没有的请下载php_curl.dll


4.重启下 apache


5.实例

//测试发送http请求
        //定义一个要发送的目标URL;
        $url = "http://www.xxx.com";
        //定义传递的参数数组;
        $data['aaa'] = 'aaaaa';
        $data['bbb'] = 'bbbb';
        //定义返回值接收变量;
        $httpstr = http($url, $data, 'POST', array("Content-type: text/html; charset=utf-8"));
        dump($httpstr);


待续

你可能感兴趣的:(php)