利用curl或者file_get_contents获取远程http的内容时,成功。但是获取https的内容时,失败。错误提示文字类似于:
SSL operation failed with code 1. OpenSSL Error messages: error:14090086: SSL routines:ssl3_get_server_certificate:certificate vertify failed
1、保证php.ini里面的openssl扩展肯定要打开。这个操作比较基础,不做赘述。
extension=openssl.so
2、查看一下openssl证书的默认位置,检测openssl的证书位置的代码:
php -r "print_r(openssl_get_cert_locations());"
default_cert_file是默认位置。
3、下载更新证书
下载网址:https://curl.haxx.se/docs/caextract.html
选择一个最新的perm证书下载即可,下载好的证书要放置在上述默认位置或者自定义好的位置,重启php后,就应该可以解决问题了。
]]>composer require phpoffice/phpspreadsheet
PhpSpreadsheet中文简介
phpexcel由于版本陈旧性能低下官方放弃维护,转而开发PhpSpreadsheet用了最新得psr标准因而对php版本不向下兼容需要注意!
PhpSpreadsheet是一个用纯PHP编写的库,提供了一组类,使您可以读取和写入不同的电子表格文件格式
PhpSpreadsheet提供了丰富的API接口,可以设置诸多单元格以及文档属性,包括样式、图片、日期、函数等等诸多应用,总之你想要什么样的Excel表格,PhpSpreadsheet都能做到
使用PhpSpreadsheet开发的PHP要求7.1或更高版本,并且支持链式操作
PhpSpreadsheet 支持的文件格式
文件路径extend/Excel.php
<?php
use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
use PhpOffice\PhpSpreadsheet\IOFactory;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use think\exception\ValidateException;
class Excel
{
/**
* 导入excel表格
* @param array $file 文件路径
* @return array|string
*/
protected function importExcel($file)
{
try {
// 截取后缀
$fileExtendName = substr(strrchr($file, '.'), 1);
// 有Xls和Xlsx格式两种
if ($fileExtendName == 'xlsx') {
$objReader = IOFactory::createReader('Xlsx');
} else {
$objReader = IOFactory::createReader('Xls');
}
// 设置文件为只读
$objReader->setReadDataOnly(TRUE);
// 读取文件,tp6默认上传的文件,在runtime的相应目录下,可根据实际情况自己更改
$objPHPExcel = $objReader->load($_SERVER['DOCUMENT_ROOT'] . $file);
//excel中的第一张sheet
$sheet = $objPHPExcel->getSheet(0);
// 取得总行数
$highestRow = $sheet->getHighestRow();
// 取得总列数
$highestColumn = $sheet->getHighestColumn();
Coordinate::columnIndexFromString($highestColumn);
$lines = $highestRow - 1;
if ($lines <= 0) {
return '数据不能为空';
}
// 直接取出excle中的数据
$data = $objPHPExcel->getActiveSheet()->toArray();
// 删除第一个元素(表头)
array_shift($data);
// 返回结果
return $data;
} catch (ValidateException $e) {
return $e->getMessage();
}
}
/**
* 导出excel表格
* @param array $header 设置表头数据
* @param array $data 生成的表格数据
* @param bool $type 文件类型,true为Xlsx,false为Xls,默认为true
* @param string $fileName 文件名,默认为数据
*/
protected function export($header = [], $data = [], $type = true, $fileName = "数据")
{
// 实例化类
$preadsheet = new Spreadsheet();
// 创建sheet
$sheet = $preadsheet->getActiveSheet();
// 生成表头字母
$letter = [];
$n = 0;
for ($i = 'A'; $i <= 'Z'; $i++) {
if ($n<count($header)){
$letter[] = $i;
}else{
break;
}
$n++;
}
// 循环设置表头数据
foreach ($header as $k => $v) {
// 解决长数字自动转科学计数法
if(is_numeric($v) && strlen($v) > 11){
$sheet->setCellValueExplicit($letter[$k].'1',$v,'s');
}
$sheet->setCellValue($letter[$k].'1', $v);
}
// 生成数据
$sheet->fromArray($data, null, "A2");
// 样式设置
$sheet->getDefaultColumnDimension()->setWidth(12);
// 设置下载与后缀
if ($type) {
header("Content-Type:application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
$type = "Xlsx";
$suffix = "xlsx";
} else {
header("Content-Type:application/vnd.ms-excel");
$type = "Xls";
$suffix = "xls";
}
// 激活浏览器窗口
header("Content-Disposition:attachment;filename=$fileName.$suffix");
//缓存控制
header("Cache-Control:max-age=0");
// 调用方法执行下载
$writer = IOFactory::createWriter($preadsheet, $type);
// 数据流
$writer->save("php://output");
}
}
调用
$excel = new Excel();
// 导出
$header = ['姓名','性别'];
$data = [['小王','男'],['小李','男']];
$excel->export($header,$data);
// 导入
$data = $excel->importExcel('/storage/picture/20221222/77d80064c35db092c8124a13a7f6fcd5.xlsx');
if(is_array($data)){
print_r($data);
}else{
echo $data;
}
]]>浮点型
又称为精度类型,是一种可能丢失精度的数据类型,数据可能不那么准确
float 单精度类型
4字节存储,7位精度,表示数据范围比整数大得多
float 表示不指定小数位的浮点数
float(M, D)表示一共存储M个有效数字,其中小数部分占D位
double 双精度类型
8个字节存储,表示范围更大,精度有15位左右
double 表示不指定小数位的浮点数
double(M, D)表示一共存储M个有效数字,其中小数部分占D位
如何选择
当需要存储的小数对精度要求不高时,可以选择FLOAT单精度浮点型,可以节省内存空间,提高计算速度。
当需要进行高速数学计算、科学计算、卫星定位计算等对精度要求较高时,可以选择DOUBLE双精度浮点型。
当需要进行精确计算,如工资结算、转账打款等财务类型的数据,可以选择DECIMAL定点型。
Chinese
(中文)
HTML Snippets
(代码提示)
HTML CSS Support
(智能提示CSS类名以及id)
Auto Close Tag
(自动闭合标签)
Auto Rename Tag
(自动重命名 HTML 标签的开始和结束标签)
CSS Peek
(选择某个 class 或者 id 名称按住Ctrl键+鼠标左键可以直接定位到该名称的CSS的位置)
Markmap
(思维导图神器,.md文档编辑窗口的右上角就会多一个预览的图标Open as markmap,当然也可手动打开命令面板,输入Open as markmap)
css-auto-prefix
(自动添加 CSS 私有前缀)
JavaScript (ES6) code snippets
(智能提示与快速输入)
jQuery Code Snippets
(jQuery代码智能提示)
px to rem & rpx & vw (cssrem)
(px转换成rem,Font Size:填写设计稿的宽度/10)
需要在head引用lib-flexible:https://zhizun.lanzouy.com/iq8cDzuud2f
<script>
if(window.screen.width >= 850){// 设置最大的字体大小,PC端显示,放到head
document.getElementsByTagName('html')[0].style.fontSize = '85px';
}
</script>
PHP Intelephense
(PHP代码提示工具)
open in browser
(快速打开html文件到浏览器预览)
Prettier - Code formatter
(文件格式化,可配置自动格式化)
Vetur
(官方钦定Vue插件)
Vue Language Features
(默认的vue文件在vs code里全部是一样的文字,且不能点击。该插件让vue文件的内容有了颜色区分,同时支持点击相对路径文件的跳转)
Preview on Web Server
(html文件保存,浏览器自动刷新,右键选择vscode-preview-server: Launch on browser,启动浏览器,需要使用本地web服务器,去掉右上角刷新提示:<style>#__bs_notify__{ display: none!important; }</style>
)
二、效率神器
Bracket Pair Colorizer
(括号做颜色区分)
Browser Preview
(VSCode里面打开浏览器)
REST Client
(接口调试)
Partial Diff
(文件比较)
Npm Intellisense
(自动完成导入语句中的npm模块)
Path Intellisense
(快速引入文件)
Color Highlight
(设置 CSS 颜色的样式)
Project Dashboard
(项目仪表板插件)
CodeSnap
(代码截图插件)
Path Autocomplete
(路径自动完成)
IntelliCode
(提供智能的代码建议,默认支持 Python、TypeScript/JavaScript、React 和 Java)
ES7 React/Redux/GraphQL/React-Native snippets
(语法智能提示,React 开发者必备)
Live SASS Compiler
(可以将 SASS 或 SCSS 文件实时编译或转译为 CSS 文件)
Remote-SSH
(SSH 服务器的远程机器作为开发环境)
Debugger for chrome
(微软开发的插件,调试 JS 代码,可以设置断点、逐步执行代码、调试动态添加的脚本等)
Live Server
(实时加载功能的小型服务器)
Minify
(压缩html、css、js文件,安装后按F1再输入Minify)
Regex Previewer
(实时预览正则表达式的效果)
HTML Boilerplate
(一键生成 HTML 模板)
wakatime
(编程时间及行为跟踪统计)
any-rule
(常用正则大全)
Image preview
(预览图片)
Tabnine
(多语言的插件,自动完成代码的输入)
Settings Sync
(配置同步到云端,登录账号也会同步扩展)
Codelf
(提供很多建议的命名,选中文本再右键点击Codelf)
Highlight Matching Tag
(突出显示匹配的开始和/或结束标签)
Turbo Console Log
(快速添加 console.log 信息,js debug 必备,ctrl + alt + l 选中变量之后,使用这个快捷键生成 console.log,alt + shift + c 注释所有 console.log,alt + shift + u 启用所有 console.log,alt + shift + d 删除所有 console.log)
Sort lines
(对当前文本排序)
Data Preview
(预览数据文件)
三、Git集成
GitHub Pull requests
( 查看和管理GitHub拉取请求和问题)
Git Graph
(Git 图形化显示和操作)
GitLens
(快速查看更改行或代码块的对象)
GitHistory
(可查看和搜索git日志以及图形和详细信息)
四、美化
GitHub Theme
(黑白两款皮肤)
vscode-icons
(漂亮的目录树图标主题)
Better Align
(代码优雅排版)
Better Comments
(丰富注释颜色)
vscode-json
(处理 JSON 文件)
Prettier
(格式化插件支持React)
Material Theme
(集成了多种主题皮肤)
Material Icon Theme
(扁平化的主题图标库)
Beautify
(右键鼠标一键格式化)
五、代码规范
change-case
(变量命名规范)
JavaScript Booster
(代码改进)
ESlint
(严谨的规范书写)
TSLint
(书写规范)
Code Spell Checker
(拼写检查程序)
koroFileHeader
(生成文件头部注释和函数注释)
Error Lens
(代码检查(错误、警告、语法问题)进行突出显示)
EditorConfig for VS Code
(代码风格统一)
六、装X神器
Markdown All in One
(书写Markdown)
vscode-drawio
(画流程图)
Polacode-2020
(转化成一张逼格满满的图片)
Live Share
(与他人实时进行协作式编辑和调试)
Markdown Preview Enhanced
(在 VSCode 里编写 Markdown,支持预览)
1. extend 目录的直接子内容
假设在 extend 目录下创建一个 Upload.php 文件,如果是 extend 目录的直接子内容则不需要添加命名空间
<?php
class Upload
{
}
此时可以在控制器中直接使用 \Upload 类,特别注意命名空间
2. 带层级的类
假设在 extend/file 目录下创建一个 Upload.php 文件,此时需要添加命名空间
<?php
namespace file;
class Upload
{
}
此时可以在控制器中直接使用 \file\Upload 类
// 测试
dump(new \Upload());
dump(new \file\Upload());
]]><?php
class Cache
{
/**
* 缓存目录
* @var
*/
private $cache_dir;
/**
* @param $cache_dir
* @throws Exception
*/
public function __construct($cache_dir)
{
$this->cache_dir = $cache_dir;
if (!is_dir($cache_dir)) {
$make_dir_result = mkdir($cache_dir, 0755, true);
if ($make_dir_result === false) throw new Exception('Cannot create the cache directory');
}
}
/**
* 根据key获取值,会判断是否过期
* @param $key
* @return mixed
*/
public function get($key)
{
$cache_data = $this->getItem($key);
if ($cache_data === false || !is_array($cache_data)) return false;
return $cache_data['data'];
}
/**
* 添加或覆盖一个key
* @param $key
* @param $value
* @param $expire
* @return mixed
*/
public function set($key, $value, $expire = 0)
{
return $this->setItem($key, $value, time(), $expire);
}
/**
* 设置包含元数据的信息
* @param $key
* @param $value
* @param $time
* @param $expire
* @return bool
*/
private function setItem($key, $value, $time, $expire)
{
$cache_file = $this->createCacheFile($key);
if ($cache_file === false) return false;
$cache_data = array('data' => $value, 'time' => $time, 'expire' => $expire);
$cache_data = json_encode($cache_data);
$put_result = file_put_contents($cache_file, $cache_data);
if ($put_result === false) return false;
return true;
}
/**
* 创建缓存文件
* @param $key
* @return bool|string
*/
private function createCacheFile($key)
{
$cache_file = $this->path($key);
if (!file_exists($cache_file)) {
$directory = dirname($cache_file);
if (!is_dir($directory)) {
$make_dir_result = mkdir($directory, 0755, true);
if ($make_dir_result === false) return false;
}
$create_result = touch($cache_file);
if ($create_result === false) return false;
}
return $cache_file;
}
/**
* 判断Key是否存在
* @param $key
* @return mixed
*/
public function has($key)
{
$value = $this->get($key);
if ($value === false) return false;
return true;
}
/**
* 加法递增
* @param $key
* @param int $value
* @return mixed
*/
public function increment($key, $value = 1)
{
$item = $this->getItem($key);
if ($item === false) {
$set_result = $this->set($key, $value);
if ($set_result === false) return false;
return $value;
}
$check_expire = $this->checkExpire($item);
if ($check_expire === false) return false;
$item['data'] += $value;
$result = $this->setItem($key, $item['data'], $item['time'], $item['expire']);
if ($result === false) return false;
return $item['data'];
}
/**
* 减法递增
* @param $key
* @param int $value
* @return mixed
*/
public function decrement($key, $value = 1)
{
$item = $this->getItem($key);
if ($item === false) {
$value = 0 - $value;
$set_result = $this->set($key, $value);
if ($set_result === false) return false;
return $value;
}
$check_expire = $this->checkExpire($item);
if ($check_expire === false) return false;
$item['data'] -= $value;
$result = $this->setItem($key, $item['data'], $item['time'], $item['expire']);
if ($result === false) return false;
return $item['data'];
}
/**
* 删除一个key,同时会删除缓存文件
* @param $key
* @return mixed
*/
public function delete($key)
{
$cache_file = $this->path($key);
if (file_exists($cache_file)) {
$unlink_result = unlink($cache_file);
if ($unlink_result === false) return false;
}
return true;
}
/**
* 清除所有缓存
* @return mixed
*/
public function clear()
{
return $this->delTree($this->cache_dir);
}
/**
* 递归删除目录
* @param $dir
* @return bool
*/
function delTree($dir)
{
$files = array_diff(scandir($dir), array('.', '..'));
foreach ($files as $file) {
is_dir("$dir/$file") ? $this->delTree("$dir/$file") : unlink("$dir/$file");
}
return rmdir($dir);
}
/**
* 根据key获取缓存文件路径
*
* @param string $key
* @return string
*/
protected function path($key)
{
$parts = array_slice(str_split($hash = md5($key), 2), 0, 2);
return $this->cache_dir . '/' . implode('/', $parts) . '/' . $hash;
}
/**
* 获取含有元数据的信息
* @param $key
* @return bool|mixed|string
*/
protected function getItem($key)
{
$cache_file = $this->path($key);
if (!file_exists($cache_file) || !is_readable($cache_file)) {
return false;
}
$cache_data = file_get_contents($cache_file);
if (empty($cache_data)) return false;
$cache_data = json_decode($cache_data, true);
if ($cache_data) {
$check_expire = $this->checkExpire($cache_data);
if ($check_expire === false) {
$this->delete($key);
return false;
}
}
return $cache_data;
}
/**
* 检查key是否过期
* @param $cache_data
* @return bool
*/
protected function checkExpire($cache_data)
{
$time = time();
$is_expire = intval($cache_data['expire']) !== 0 && (intval($cache_data['time']) + intval($cache_data['expire']) < $time);
if ($is_expire) return false;
return true;
}
}
使用方法
include('Cache.class.php');
$cache = new Cache($_SERVER['DOCUMENT_ROOT'].'/cache');
// 添加或覆盖
$cache->set('name','admin',3600);// 过期时间默认为0,不限制
// 获取
$cache->get('name');
// 删除
$cache->delete('name');
// 清空
$cache->clear();
]]><?php
header("Content-Type: application/octet-stream");
$filename = "1.txt";
$content = '这里是需要生成文件的内容';
$ua = $_SERVER["HTTP_USER_AGENT"];
$encoded_filename = urlencode($filename);
$encoded_filename = str_replace("+", "%20", $encoded_filename);
if (preg_match("/MSIE/", $ua)) {
header('Content-Disposition: attachment; filename="' . $encoded_filename . '"');
} else if (preg_match("/Firefox/", $ua)) {
header('Content-Disposition: attachment; filename*="' . $filename . '"');
} else {
header('Content-Disposition: attachment; filename="' . $filename . '"');
}
echo $content;
]]><?php
/**
* cookie加密登录与验证
* @param array $userInfo 用户信息
* @param bool $validate 是否为验证或者填入token值验证,默认为false
* @param int $expiresTime 过期时间,默认为1天
* @param string $tag token标签,默认为zz_token
* @return bool|string
*/
function zz_login($userInfo, $validate = false, $expiresTime = 1, $tag = 'zz_token')
{
$salt = zz_salt();
$host = $_SERVER['HTTP_HOST'];
if (!$salt) {
return false;
}
if (!$validate) {
try {
$expiresTime = time() + 3600 * 24 * $expiresTime;
$token = base64_encode(json_encode(['userInfo' => $userInfo, 'domain' => $host, 'expiresTime' => $expiresTime, 'code' => md5(json_encode($userInfo) . $host . $expiresTime . $salt)]));
setcookie($tag, $token, $expiresTime, '/');
return $token;
} catch (Exception $e) {
return false;
}
} else {
if($validate === true){
if (empty($_COOKIE[$tag])) {
return false;
}
$arr = json_decode(base64_decode($_COOKIE[$tag]), true);
}else{
$arr = json_decode(base64_decode($validate), true);
}
if (empty($arr['userInfo']) || empty($arr['domain']) || $arr['domain'] != $host || empty($arr['code']) || empty($arr['expiresTime']) || $arr['expiresTime'] <= time()) {
return false;
}
return $arr['code'] === md5(json_encode($arr['userInfo']) . $host . $arr['expiresTime'] . $salt);
}
return true;
}
/**
* 生成安全码
* @return string
*/
function zz_salt()
{
$root = $_SERVER['DOCUMENT_ROOT'];
$file = $root.'/salt.php';
if(is_file($file)){
include($file);
if(empty($salt) || empty($saltRoot) || $saltRoot != $root){
$salt = rand_str(20,true);
file_put_contents($file,"<?php \r\n\$salt = '{$salt}';\r\n\$saltRoot = '{$root}';");
}
}else{
$salt = rand_str(20,true);
file_put_contents($file,"<?php \r\n\$salt = '{$salt}';\r\n\$saltRoot = '{$root}';");
}
return $salt;
}
/**
* 生成随机字符串
* @param int $num 字符串位数,默认为6
* @param bool $special 使用特殊字符,默认为false
* @return string
*/
function rand_str($num = 6,$special = false)
{
$str = 'abcedfghjkmnpqrstuvwxyzABCEDFGHJKMNPQRSTUVWXYZ0123456789';
if($special){
$str .= '!@#$%^&*';
}
return substr(str_shuffle($str), 0, $num);
}
// 登录
$userInfo = ['id' => 1,'username' => 'admin'];
zz_login($userInfo);
// 验证
if(zz_login('',true)){
echo '登录';
}else{
echo '未登录';
}
// 获取用户信息
$arr = json_decode(base64_decode($_COOKIE['zz_token']),true);
print_r($arr['userInfo']);
]]><?php
//让程序一直运行
set_time_limit(0);
//设置程序运行内存
ini_set('memory_limit', '128M');
$fileName = '数据';
header('Content-Encoding: UTF-8');
header("Content-type:application/vnd.ms-excel;charset=UTF-8");
header('Content-Disposition: attachment;filename="' . $fileName . '.csv"');
//打开php标准输出流
$fp = fopen('php://output', 'a');
//添加BOM头,以UTF8编码导出CSV文件,如果文件头未添加BOM头,打开会出现乱码。
fwrite($fp, chr(0xEF).chr(0xBB).chr(0xBF));
//添加导出标题
fputcsv($fp, ['姓名', '年龄', '地区']);
$page = 1;//当前页数
$limit = 5000; //每次导出数量
while(1==1){
$limit_offset = ($page - 1) * $limit;
$data = $this->where($where)->order('id desc')->limit($limit_offset,$limit)->select()->toArray();
if(!$data){
break;
}
foreach ($data as $v) {
fputcsv($fp, $v);
}
//达到导出数量就刷新缓冲区
ob_flush();
flush();
$page++;
}
]]><?php
class wc
{
public function __construct($who)
{
echo "{$who}准备去上厕所了";
}
public function go()
{
echo "1.跑出了教室";
return $this;
}
public function action($ss)
{
echo $ss . "2.到了厕所,开始尿尿";
return $this;
}
public function back()
{
echo "3.尿尿结束,回到教室";
return $this;
}
}
$xm = new wc("小明");
$xm->go()->action("<br>")->back();
]]>