diff --git a/app/admin/controller/Article.php b/app/admin/controller/Article.php index 1a3d4d3..9bc6116 100644 --- a/app/admin/controller/Article.php +++ b/app/admin/controller/Article.php @@ -89,6 +89,7 @@ class Article extends AuthController if ($data['title'] == "") return app("json")->fail("文章名称不能为空"); if ($data['category_id'] == "") return app("json")->fail("栏目分类不能为空"); if ($data['cover_path'] == "") return app("json")->fail("主图不能为空"); + $error = ""; try { $data['author'] = $data['author'] ?: $this->adminInfo['nickname']; $data['uid'] = $this->adminId; @@ -108,6 +109,7 @@ class Article extends AuthController if ($id == "") { $data['uid'] = $this->adminInfo['uid']; $data['author'] = $data['author'] ?: $this->adminInfo['nickname']; + $data['create_date'] = date("Y-m-d"); $data['create_time'] = time(); $data['update_time'] = time(); $id = aModel::insertGetId($data); @@ -147,9 +149,10 @@ class Article extends AuthController $res = true; } catch (Exception $e) { Log::error('文章修改失败:失败原因:' . $e->getMessage()); + $error = $e->getMessage(); $res = false; } - return $res ? app("json")->success("操作成功", 'code') : app("json")->fail("操作失败"); + return $res ? app("json")->success("操作成功", 'code') : app("json")->fail("操作失败,错误原因:".$error); } diff --git a/app/admin/view/article/add.html b/app/admin/view/article/add.html index b97c365..6083161 100644 --- a/app/admin/view/article/add.html +++ b/app/admin/view/article/add.html @@ -59,7 +59,7 @@
  • - diff --git a/app/admin/view/article/edit.html b/app/admin/view/article/edit.html index 2700539..da5691d 100644 --- a/app/admin/view/article/edit.html +++ b/app/admin/view/article/edit.html @@ -63,7 +63,7 @@
  • - diff --git a/app/admin/view/article/index.html b/app/admin/view/article/index.html index 7886bd1..df64645 100644 --- a/app/admin/view/article/index.html +++ b/app/admin/view/article/index.html @@ -129,8 +129,9 @@ field: 'operate', title: '操作', formatter: function (value, row, index) { - let html = '\n' + + let html = '\n' + + '\n' + '\n'; return html; }, diff --git a/app/common/constant/Data.php b/app/common/constant/Data.php index 589b98f..6952d77 100644 --- a/app/common/constant/Data.php +++ b/app/common/constant/Data.php @@ -15,6 +15,7 @@ class Data const CURR_CATEGORY_PATENT_ID = 'curr_category_patent_id'; //当前分类父级id const DATA_SYSTEM_CONFIG = 'data_system_config'; //系统配置 const DATA_ADVERT = 'data_advert'; //广告 + const DATA_ARCHIVE = "data_archive"; //文章归档 //广告位 const ADVERT_NAV_LIST = [ diff --git a/app/common/taglib/Ape.php b/app/common/taglib/Ape.php index 196b973..4649a13 100644 --- a/app/common/taglib/Ape.php +++ b/app/common/taglib/Ape.php @@ -23,6 +23,7 @@ class Ape extends TagLib 'comment' => ['attr' => 'typeId,void,type,pageSize,orderBy', 'close' => 1], 'relevant' => ['attr' => 'id,model,void,row', 'close' => 1], 'tags' => ['attr' => 'tags,void', 'close' => 1], + 'archive' => ['attr' => 'type,format,void', 'close' => 1], ]; @@ -162,8 +163,8 @@ class Ape extends TagLib $cid = isset($tag['cid']) ? $tag['cid'] : '$cid'; $void = isset($tag['void']) ? $tag['void'] : 'field'; $none = isset($tag['none']) ? $tag['none'] : '没有了'; - $parse = ''; $parse .= '{volist name="__LIST__" id="' . $void . '"}'; @@ -254,9 +255,9 @@ class Ape extends TagLib $void = isset($tag['void']) ? $tag['void'] : 'field'; $parse = ''; - $parse .= '{volist name="$__TAG_LIST__" id="' . $void . '"}'; + $parse .= '{volist name="$__LIST__" id="' . $void . '"}'; $parse .= $content; $parse .= '{/volist}'; return $parse; @@ -316,4 +317,27 @@ class Ape extends TagLib $parse .= '{/volist}'; return $parse; } + + /** + * 文章归档 + * @param $tag + * @param $content + * @return bool|string + */ + public function tagArchive($tag, $content) + { + if (empty($tag['type'])) { + return false; + } + $format = $tag['format']?:"Y-m"; + $void = isset($tag['void']) ? $tag['void'] : 'field'; + $parse = ''; + $parse .= '{volist name="$__LIST__" id="' . $void . '"}'; + $parse .= $content; + $parse .= '{/volist}'; + return $parse; + } + } \ No newline at end of file diff --git a/app/index/common.php b/app/index/common.php index ab75d59..c268ce8 100644 --- a/app/index/common.php +++ b/app/index/common.php @@ -591,15 +591,52 @@ function tpl_get_advert($type, $row) } else { $advertList = Db::name('advert')->where('status', 1)->order('sort desc')->limit($row)->select(); } + //处理文件cdn信息 + foreach ($advertList as $key => &$item) { + if (empty($item['cover_path'])){ + unset($advertList[$key]); + } + $item['cover_path'] = file_cdn($item['cover_path']); + } cache(Data::DATA_ADVERT . '_' . $type, $advertList); } - $advertListTemp = []; - foreach ($advertList as $key => $item) { - if ($item['cover_path']) { - array_push($advertListTemp, $item); + return $advertList; +} + +/** + * 文档归档 + * @ 格式 tpl_get_archive_list("month","Y-m") tpl_get_archive_list("month","Y年-m月").... + * @param $type + * @param $format + * @return mixed + * @author 李玉坤 + * @date 2022-06-01 10:06 + */ +function tpl_get_archive_list($type,$format){ + $list = cache(Data::DATA_ARCHIVE . '_' . $type); + $list = null; + if ($list === null) { + switch ($type){ + case "month": + $dateFormat = "LEFT(create_date,7)"; + break; + case "day": + $dateFormat = "create_date"; + break; + case "year": + $dateFormat = "LEFT(create_date,4)"; + break; + default: + $dateFormat = "create_date"; + break; } + $list = $documentListModel = (new Document())->group($dateFormat)->column("count(*) as count,create_date"); + foreach ($list as $key => &$item) { + $item['create_date'] = date($format,strtotime($item['create_date'])); + } + cache(Data::DATA_ADVERT . '_' . $type, $list); } - return $advertListTemp; + return $list; } if (!function_exists('web_config')) { diff --git a/public/install/ape_blog.sql b/public/install/ape_blog.sql index aca0542..8424731 100644 --- a/public/install/ape_blog.sql +++ b/public/install/ape_blog.sql @@ -11,7 +11,7 @@ Target Server Version : 50726 File Encoding : 65001 - Date: 28/02/2022 14:42:06 + Date: 01/06/2022 10:23:26 */ SET NAMES utf8mb4; @@ -106,7 +106,7 @@ INSERT INTO `ape_admin_auth` VALUES (26, '主题管理', 'mdi mdi-store', 0, 'ad INSERT INTO `ape_admin_auth` VALUES (27, '主题管理', '', 26, 'admin', 'theme', 'index', '', '', 0, 0, 1, '/admin/theme/index', 0, 1, '1', '', 1613400349, 1582093161); INSERT INTO `ape_admin_auth` VALUES (28, '主题商店', '', 26, 'admin', 'theme', 'store', '', '', 0, 0, 0, '/admin/theme/store', 0, 1, '1', '1', 1613400389, 1642946978); INSERT INTO `ape_admin_auth` VALUES (29, '友链管理', 'mdi mdi-account-card-details', 0, 'admin', 'friend_link', 'index', '', '', 0, 0, 1, '/admin/friend_link/index', 0, 1, '1', '1', 1613400510, 1642947636); -INSERT INTO `ape_admin_auth` VALUES (30, '友链列表', '', 34, 'admin', 'friendlink', 'index', '', '', 0, 0, 1, '/admin/friend_link/index', 0, 1, '1', '', 1613400539, 1582093161); +INSERT INTO `ape_admin_auth` VALUES (30, '友链列表', '', 34, 'admin', 'friendlink', 'index', '', '', 0, 0, 1, '/admin/friendlink/index', 0, 1, '1', '', 1613400539, 1582093161); INSERT INTO `ape_admin_auth` VALUES (31, '数据库管理', '', 8, 'admin', 'databases', 'index', '', '', 0, 0, 1, '/admin/databases/index', 0, 1, '1', '', 1635572569, 1635572671); INSERT INTO `ape_admin_auth` VALUES (32, '友链管理', '', 29, 'admin', 'friend_link', 'index', '', '', 0, 0, 1, '/admin/friend_link/index', 0, 1, '1', '1', 1642089882, 1642947643); @@ -298,6 +298,7 @@ CREATE TABLE `ape_document` ( `keywords` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '', `description` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT '描述', `sort` int(10) NOT NULL DEFAULT 0 COMMENT '排序', + `create_date` date NOT NULL COMMENT '创建日期', `create_time` int(10) UNSIGNED NOT NULL DEFAULT 0 COMMENT '创建时间', `update_time` int(10) UNSIGNED NOT NULL DEFAULT 0 COMMENT '更新时间', `status` tinyint(4) NOT NULL DEFAULT 0 COMMENT '数据状态', @@ -306,12 +307,118 @@ CREATE TABLE `ape_document` ( UNIQUE INDEX `alias`(`alias`) USING BTREE, INDEX `idx_category_status`(`category_id`, `status`) USING BTREE, INDEX `idx_status_type_pid`(`status`, `uid`) USING BTREE -) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '文档模型基础表' ROW_FORMAT = DYNAMIC; +) ENGINE = InnoDB AUTO_INCREMENT = 110 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '文档模型基础表' ROW_FORMAT = DYNAMIC; -- ---------------------------- -- Records of ape_document -- ---------------------------- -INSERT INTO `ape_document` VALUES (1, 'about', 1, '超级管理员', '关于源码云博客', 1, 'http://apeblog.io/upload/image/20220228/05e4cabf56f07a0e39337dc1ce63867a.png', 'article', '', 1, 1, 1, '', 1, 88, '源码云,博客,源码云博客', '关于源码云博客', '源码云博客,源码云,博客,关于', '源码云博客最好用的博客程序', 98, 1642089660, 1646011628, 1, ''); +INSERT INTO `ape_document` VALUES (1, 'about', 1, '超级管理员', '关于源码云博客', 1, '/upload/image/image/20220228/05e4cabf56f07a0e39337dc1ce63867a.png', 'article', '', 1, 1, 1, '', 1, 92, '源码云,博客,源码云博客', '关于源码云博客', '源码云博客,源码云,博客,关于', '源码云博客最好用的博客程序', 98, '2022-01-14', 1642089660, 1646011628, 1, ''); +INSERT INTO `ape_document` VALUES (2, '2', 1, '超级管理员', '原生php 文件列表遍历方法', 3, '/upload/image/2017-07-31/597ef3ca022ed.png', 'article', '', 0, 0, 0, '', 1, 90, '', '', '', '', 0, '2017-07-31', 1501492173, 1502097307, 1, ''); +INSERT INTO `ape_document` VALUES (3, '3', 1, '超级管理员', '原生php 获取准确浏览器类型代码', 2, '/upload/image/2017-08-01/598022ef8785b.jpg', 'article', '', 0, 0, 0, '', 1, 93, '', '', '', '', 0, '2017-08-01', 1501569778, 1502097289, 1, ''); +INSERT INTO `ape_document` VALUES (4, '4', 1, '超级管理员', 'thinkphp比较两个时间戳之间消耗时间方法', 2, '/upload/image/2017-08-07/59882e87b2f09.jpg', 'article', '', 0, 0, 0, '', 1, 74, '', '', '', '', 0, '2017-08-07', 1502097034, 1502097255, 1, ''); +INSERT INTO `ape_document` VALUES (5, '5', 1, '超级管理员', 'linux 安装php拓展,版本不匹配的解决办法', 3, '/upload/image/2017-08-08/598925c580246.png', 'article', '', 0, 0, 0, '', 1, 82, '', '', '', '', 0, '2017-08-08', 1502160327, 1502160327, 1, ''); +INSERT INTO `ape_document` VALUES (6, '6', 1, '超级管理员', 'CI 3.X 系列 session 设置 session 路径创建失败问', 3, '/upload/image/2017-09-26/59c9bea994d51.png', 'article', '', 0, 0, 0, '', 1, 97, '', '', '', '', 0, '2017-09-26', 1506393771, 1506393771, 1, ''); +INSERT INTO `ape_document` VALUES (7, '7', 1, '超级管理员', 'thinkphp 使用iframe类框架跳转问题', 2, '/upload/image/2017-11-17/5a0e554b1c465.png', 'article', '', 0, 0, 0, '', 1, 81, '', '', '', '', 0, '2017-11-17', 1510888781, 1510906941, 1, ''); +INSERT INTO `ape_document` VALUES (8, '8', 1, '超级管理员', 'Win10风格前端解决方案 扒站源码', 31, '/upload/image/2017-11-17/5a0e5753dc61b.png', 'article', '', 0, 0, 0, '', 1, 126, '', '', '', '', 0, '2017-11-17', 1510889420, 1568253320, 1, ''); +INSERT INTO `ape_document` VALUES (9, '9', 1, '超级管理员', 'Redis Session共享类,【负载均衡使用】', 30, '/upload/image/2017-11-17/5a0e59e32e8d6.jpg', 'article', '', 0, 0, 0, '', 1, 110, '', '', '', '', 0, '2017-11-17', 1510889958, 1510889958, 1, ''); +INSERT INTO `ape_document` VALUES (10, '10', 1, '超级管理员', 'CI 3.x 使用iframe类框架跳转问题', 30, '/upload/image/2017-11-17/5a0ea4b40ec3a.png', 'article', '', 0, 0, 0, '', 1, 117, '', '', '', '', 0, '2017-11-17', 1510909110, 1510909135, 1, ''); +INSERT INTO `ape_document` VALUES (11, '11', 1, '超级管理员', 'php 调用ffmpeg获取视频信息的方法', 30, '/upload/image/2017-11-25/5a18aa36e6058.jpg', 'article', '', 0, 0, 0, '', 1, 114, '', '', '', '', 0, '2017-11-25', 1511565881, 1511565881, 1, ''); +INSERT INTO `ape_document` VALUES (12, '12', 1, '超级管理员', '超级简单的 Nginx 反代网站教程', 22, '/upload/image/2017-11-27/5a1be72822fb9.jpg', 'article', '', 0, 0, 0, '', 1, 82, '', '', '', '', 0, '2017-11-27', 1511778090, 1511778090, 1, ''); +INSERT INTO `ape_document` VALUES (13, '13', 1, '超级管理员', 'ffmpeg 视频抽取音频,视音频分离', 22, '/upload/image/2017-11-29/5a1e5675d3476.jpg', 'article', '', 0, 0, 0, '', 1, 77, '', '', '', '', 0, '2017-11-29', 1511937656, 1511937656, 1, ''); +INSERT INTO `ape_document` VALUES (14, '14', 1, '超级管理员', 'linux nfs 挂载出现 无法写入或者部分用户无法写入问题解决', 3, '/upload/image/2017-12-18/5a3728d7e751b.jpg', 'article', '', 0, 0, 0, '', 1, 82, '', '', '', '', 0, '2017-12-18', 1513564378, 1513564378, 1, ''); +INSERT INTO `ape_document` VALUES (15, '15', 1, '超级管理员', 'layui 添加不能修改的 input', 31, '/upload/image/2017-12-25/5a40d38c754ab.jpg', 'article', '', 0, 0, 0, '', 1, 115, '', '', '', '', 0, '2017-12-25', 1514197857, 1519382543, 1, ''); +INSERT INTO `ape_document` VALUES (16, '16', 1, '超级管理员', 'FFmpeg 常用命令DEMO', 22, '/upload/image/2017-12-27/5a42ffb757a23.jpg', 'article', '', 0, 0, 0, '', 1, 158, '', '', '', '', 0, '2017-12-27', 1514340282, 1514340282, 1, ''); +INSERT INTO `ape_document` VALUES (17, '17', 1, '超级管理员', 'Windows 安装php composer 显示找不到ext 目录安装失败解决', 2, '/upload/image/2018-01-03/5a4c8c0244e9d.jpg', 'article', '', 0, 0, 0, '', 1, 73, '', '', '', '', 0, '2018-01-03', 1514966020, 1514966046, 1, ''); +INSERT INTO `ape_document` VALUES (18, '18', 1, '超级管理员', 'Apache禁用测试页(默认页)', 22, '/upload/image/2018-01-03/5a4cb5ed576a3.jpg', 'article', '', 0, 0, 0, '', 1, 85, '', '', '', '', 0, '2018-01-03', 1514976751, 1514976751, 1, ''); +INSERT INTO `ape_document` VALUES (19, '19', 1, '超级管理员', '远程登录CentOS,短时间就断线的处理', 22, '/upload/image/2018-01-05/5a4f279027ef2.jpg', 'article', '', 0, 0, 0, '', 1, 78, '', '', '', '', 0, '2018-01-05', 1515136914, 1515136914, 1, ''); +INSERT INTO `ape_document` VALUES (20, '20', 1, '超级管理员', 'js作用域声明及需要注意的地方', 23, '/upload/image/2018-01-17/5a5ebeac41cd8.jpg', 'article', '', 0, 0, 0, '', 1, 105, '', '', '', '', 0, '2018-01-17', 1516158638, 1516158638, 1, ''); +INSERT INTO `ape_document` VALUES (21, '21', 1, '超级管理员', 'ffmpeng视频或音频转码命令及常用命令', 22, '/upload/image/2018-01-17/5a5ec061b1d6f.jpg', 'article', '', 0, 0, 0, '', 1, 98, '', '', '', '', 0, '2018-01-17', 1516159364, 1516269115, 1, ''); +INSERT INTO `ape_document` VALUES (22, '22', 1, '超级管理员', 'php支持断点续传的文件下载类', 2, '/upload/image/2018-01-18/5a6061eb45934.jpg', 'article', '', 0, 0, 0, '', 1, 79, '', '', '', '', 0, '2018-01-18', 1516265966, 1516265966, 1, ''); +INSERT INTO `ape_document` VALUES (23, '23', 1, '超级管理员', 'php 支持断点续传的文件下载方法和Thinkphp使用方法', 3, '/upload/image/2018-01-18/5a6062cbb49ea.jpg', 'article', '', 0, 0, 0, '', 1, 95, '', '', '', '', 0, '2018-01-18', 1516266190, 1516266253, 1, ''); +INSERT INTO `ape_document` VALUES (24, '24', 1, '超级管理员', 'git 常用命令备忘', 22, '/upload/image/2018-02-23/5a8f7cfda9159.jpg', 'article', '', 0, 0, 0, '', 1, 80, '', '', '', '', 0, '2018-02-23', 1519353087, 1519357373, 1, ''); +INSERT INTO `ape_document` VALUES (25, '25', 1, '超级管理员', 'php论坛中常用的两个时间差(多少分钟前,多少小时前,多少天前)', 2, '/upload/image/2018-02-23/5a8f8aa14d547.jpg', 'article', '', 0, 0, 0, '', 1, 87, '', '', '', '', 0, '2018-02-23', 1519356579, 1519357213, 1, ''); +INSERT INTO `ape_document` VALUES (26, '26', 1, '超级管理员', '8个常用的PHP安全函数', 2, '/upload/image/2018-02-23/5a8f8d66aaf9e.jpg', 'article', '', 0, 0, 0, '', 1, 91, '', '', '', '', 0, '2018-02-23', 1519357289, 1519357289, 1, ''); +INSERT INTO `ape_document` VALUES (27, '27', 1, '超级管理员', 'MySQL数据类型选择指南', 34, '/upload/image/2018-02-23/5a8f8f457f5e9.jpg', 'article', '', 0, 0, 0, '', 1, 122, '', '', '', '', 0, '2018-02-23', 1519357768, 1519357768, 1, ''); +INSERT INTO `ape_document` VALUES (28, '28', 1, '超级管理员', 'MySQL常用命令大全', 34, '/upload/image/2018-02-23/5a8f8f73ac342.jpg', 'article', '', 0, 0, 0, '', 1, 101, '', '', '', '', 0, '2018-02-23', 1519357843, 1519357843, 1, ''); +INSERT INTO `ape_document` VALUES (29, '29', 1, '超级管理员', '【文件/文件夹操作】php文件夹/文件目录操作函数', 2, '/upload/image/2018-02-28/5a9611d4e9ddb.jpg', 'article', '', 0, 0, 0, '', 1, 79, '', '', '', '', 0, '2018-02-28', 1519784409, 1519784409, 1, ''); +INSERT INTO `ape_document` VALUES (30, '30', 1, '超级管理员', 'thinkphp多表查询两表有重复相同字段解决方法', 3, '/upload/image/2018-03-02/5a98c308a7dda.jpg', 'article', '', 0, 0, 0, '', 1, 91, '', '', '', '', 0, '2018-03-02', 1519960842, 1519960842, 1, ''); +INSERT INTO `ape_document` VALUES (31, '31', 1, '超级管理员', 'php文件夹遍历的N种办法', 2, '/upload/image/2018-03-12/5aa5f607c2ec8.jpg', 'article', '', 0, 0, 0, '', 1, 97, '', '', '', '', 0, '2018-03-12', 1520825866, 1520825866, 1, ''); +INSERT INTO `ape_document` VALUES (32, '32', 1, '超级管理员', '借助jquery插件实现高斯模糊背景', 24, '/upload/image/2018-03-15/5aaa310d7d0ec.png', 'article', '', 0, 0, 0, '', 1, 131, '', '', '', '', 0, '2018-03-15', 1521103154, 1521103154, 1, ''); +INSERT INTO `ape_document` VALUES (33, '33', 1, '超级管理员', 'mysql常用语句及复习资料', 34, '/upload/image/2018-03-19/5aaf69d92507f.jpg', 'article', '', 0, 0, 0, '', 1, 163, '', '', '', '', 0, '2018-03-19', 1521445343, 1521445343, 1, ''); +INSERT INTO `ape_document` VALUES (34, '34', 1, '超级管理员', 'html5 屏蔽全屏和下载按钮 以及屏蔽右键', 3, '/upload/image/2018-03-21/5ab209faa9958.jpg', 'article', '', 0, 0, 0, '', 1, 104, '', '', '', '', 0, '2018-03-21', 1521617404, 1521617404, 1, ''); +INSERT INTO `ape_document` VALUES (35, '35', 1, '超级管理员', 'PHP丨如何实现自判断访问是否为手机端来源', 3, '/upload/image/2018-04-04/5ac4444660b36.jpg', 'article', '', 0, 0, 0, '', 1, 120, '', '相信很多人都会在手机端背景上花心思--因为图片适应了PC端,PE端效果就惨不忍睹。适应了PE端,PC端的背景单调的可怜,对于像西顾这种完美主义者来说,一看到这种丑八怪背景就想关站跑路了。', '', '', 0, '2018-04-04', 1522810898, 1522811976, 1, ''); +INSERT INTO `ape_document` VALUES (36, '36', 1, '超级管理员', '自适应丨Html5响应式(自适应)网页设计', 3, '/upload/image/2018-04-04/5ac43e50961a0.jpg', 'article', '', 0, 0, 0, '', 1, 94, '', '', '', '', 0, '2018-04-04', 1522812283, 1522812283, 1, ''); +INSERT INTO `ape_document` VALUES (37, '37', 1, '超级管理员', 'php防止sql注入', 2, '/upload/image/2018-04-12/5acf1c92c100f.jpg', 'article', '', 0, 0, 0, '', 1, 99, '', '', '', '', 0, '2018-04-12', 1523522708, 1523522708, 1, ''); +INSERT INTO `ape_document` VALUES (38, '38', 1, '超级管理员', 'go语言基础语法结构总结', 35, '/upload/image/2018-04-20/5ad95277726c5.jpg', 'article', '', 0, 0, 0, '', 1, 122, '', '', '', '', 0, '2018-04-20', 1524191868, 1524191868, 1, ''); +INSERT INTO `ape_document` VALUES (39, '39', 1, '超级管理员', 'go自我理解数据类型', 35, '/upload/image/2018-04-20/5ad978fb05c3c.png', 'article', '', 0, 0, 0, '', 1, 105, '', '', '', '', 0, '2018-04-20', 1524199528, 1524201933, 1, ''); +INSERT INTO `ape_document` VALUES (40, '40', 1, '超级管理员', 'php使用for循环、while循环和递归写出3个函数来计算给定数列的总和', 2, '/upload/image/2018-04-20/5ad98462ea09e.jpg', 'article', '', 0, 0, 0, '', 1, 98, '', '', '', '', 0, '2018-04-20', 1524204649, 1524205107, 1, ''); +INSERT INTO `ape_document` VALUES (41, '41', 1, '超级管理员', 'php实现斐波那契数列', 2, '/upload/image/2018-04-20/5ad98dc5e0618.jpg', 'article', '', 0, 0, 0, '', 1, 90, '', '', '', '', 0, '2018-04-20', 1524207052, 1524207052, 1, ''); +INSERT INTO `ape_document` VALUES (42, '42', 1, '超级管理员', 'Go 语言类型转换', 3, '/upload/image/2018-04-20/5ad9a10a16fd8.jpg', 'article', '', 0, 0, 0, '', 1, 97, '', '', '', '', 0, '2018-04-20', 1524211979, 1524211979, 1, ''); +INSERT INTO `ape_document` VALUES (43, '43', 1, '超级管理员', '随机拿出一个0到100的数,猜数算法', 2, '/upload/image/2018-04-20/5ad9b817ea10f.jpg', 'article', '', 0, 0, 0, '', 1, 90, '', '', '', '', 0, '2018-04-20', 1524217881, 1524217960, 1, ''); +INSERT INTO `ape_document` VALUES (44, '44', 1, '超级管理员', '从mysql 查询模型解释 as 在 where中为什么不生效', 34, '/upload/image/2018-04-24/5adf09196c8db.jpg', 'article', '', 0, 0, 0, '', 1, 97, '', '', '', '', 0, '2018-04-24', 1524566301, 1524566301, 1, ''); +INSERT INTO `ape_document` VALUES (45, '45', 1, '超级管理员', 'php 面向对象 接口和抽象类', 2, '/upload/image/2018-04-26/5ae186e03f643.jpg', 'article', '', 0, 0, 0, '', 1, 87, '', '', '', '', 0, '2018-04-26', 1524729570, 1524729688, 1, ''); +INSERT INTO `ape_document` VALUES (46, '46', 1, '超级管理员', 'html添加 base解决资源路劲问题', 23, '/upload/image/2018-04-27/5ae2d152e957c.png', 'article', '', 0, 0, 0, '', 1, 112, '', '', '', '', 0, '2018-04-27', 1524814202, 1524814336, 1, ''); +INSERT INTO `ape_document` VALUES (47, '47', 1, '超级管理员', 'notepad++ 去除 扒站小偷 tel产生的冗余代码', 8, '/upload/image/2018-04-28/5ae4463396c7e.jpg', 'article', '', 0, 0, 0, '', 1, 123, '', '', '', '', 0, '2018-04-28', 1524909624, 1524909624, 1, ''); +INSERT INTO `ape_document` VALUES (48, '48', 1, '超级管理员', 'php统计脚本内存消耗和运行时间', 2, '/upload/image/2019-07-19/5d312a6e95ac8.png', 'article', '', 0, 0, 0, '', 1, 89, '', '', '', '', 0, '2019-07-19', 1563503216, 1571109951, 1, ''); +INSERT INTO `ape_document` VALUES (49, '49', 1, '超级管理员', 'setcookie刷新后才生效问题', 2, '/upload/image/2019-08-01/5d4250b0054ac.jpg', 'article', '', 0, 0, 0, '', 1, 81, '', '', '', '', 0, '2019-08-01', 1564627123, 1564627123, 1, ''); +INSERT INTO `ape_document` VALUES (50, '50', 1, '超级管理员', 'Composer 国内加速,修改镜像源', 2, '/upload/image/2019-08-22/5d5ea374df5e2.jpg', 'article', '', 0, 0, 0, '', 1, 90, '', '', '', '', 0, '2019-08-22', 1566483320, 1580887447, 1, ''); +INSERT INTO `ape_document` VALUES (51, '51', 1, '超级管理员', '视频解析接口列表', 30, '/upload/image/2019-08-23/5d5faacbafdf0.jpg', 'article', '', 0, 0, 0, '', 1, 154, '', '', '', '', 0, '2019-08-23', 1566550743, 1581504377, 1, ''); +INSERT INTO `ape_document` VALUES (52, '52', 1, '超级管理员', '参考爱奇艺全网影视做多平台融合时地址 URL自动关联转换函数', 3, '/upload/image/2019-08-29/5d676e3cc77f7.jpg', 'article', '', 0, 0, 0, '', 1, 110, '', '', '', '', 0, '2019-08-29', 1567059557, 1567059557, 1, ''); +INSERT INTO `ape_document` VALUES (53, '53', 1, '超级管理员', '页面中的http请求转为https请求', 22, '/upload/image/2019-09-12/5d79a4ae9613c.jpg', 'article', '', 0, 0, 0, '', 1, 107, '', '', '', '', 0, '2019-09-12', 1568253105, 1568253105, 1, ''); +INSERT INTO `ape_document` VALUES (54, '54', 1, '超级管理员', 'linux杀死相关所有进程', 3, '/upload/image/2019-09-16/5d7f3b6dc3b69.jpg', 'article', '', 0, 0, 0, '', 1, 101, '', '', '', '', 0, '2019-09-16', 1568619381, 1568619381, 1, ''); +INSERT INTO `ape_document` VALUES (55, '55', 1, '超级管理员', 'Linux查找并杀死僵尸进程', 22, '/upload/image/2019-09-20/5d84753455d30.jpg', 'article', '', 0, 0, 0, '', 1, 168, '', '', '', '', 0, '2019-09-20', 1568961846, 1569203732, 1, ''); +INSERT INTO `ape_document` VALUES (56, '56', 1, '超级管理员', 'QueryList 优酷列表抓取DEMO代码', 2, '/upload/image/2019-09-21/5d862aaff1e87.jpg', 'article', '', 0, 0, 0, '', 1, 189, '', '', '', '', 0, '2019-09-21', 1569073841, 1569073841, 1, ''); +INSERT INTO `ape_document` VALUES (57, '57', 1, '超级管理员', 'mac下PHPStorm2019.2破解教程', 2, '/upload/image/2019-09-22/5d8738aa5e832.jpg', 'article', '', 0, 0, 0, '', 1, 187, '', '', '', '', 0, '2019-09-22', 1569142957, 1569142957, 1, ''); +INSERT INTO `ape_document` VALUES (58, '58', 1, '超级管理员', 'MySQL查询和删除重复记录', 34, '/upload/image/2019-09-29/5d906140d7e76.jpg', 'article', '', 0, 0, 0, '', 1, 204, '', '', '', '', 0, '2019-09-29', 1569743172, 1569743172, 1, ''); +INSERT INTO `ape_document` VALUES (59, '59', 1, '超级管理员', 'php foreach遍历时unset不能删除', 2, '/upload/image/2019-10-08/5d9c05649826d.jpg', 'article', '', 0, 0, 0, '', 1, 175, '', '', '', '', 0, '2019-10-08', 1570506087, 1570506107, 1, ''); +INSERT INTO `ape_document` VALUES (60, '60', 1, '超级管理员', ' macOS 下使用 PHP-version 切换 PHP 版本', 37, '/upload/image/2019-10-18/5da9d40464c99.jpg', 'article', '', 0, 0, 0, '', 1, 219, '', '', '', '', 0, '2019-10-18', 1571410951, 1571410951, 1, ''); +INSERT INTO `ape_document` VALUES (61, '61', 1, '超级管理员', '影视API接口XyplayerX3.91正式版智能影视解析系统完整版源码', 2, '/upload/image/2019-10-23/5db074224355c.jpg', 'article', '', 0, 0, 0, '', 1, 240, '', '', '', '', 0, '2019-10-23', 1571845156, 1580887418, 1, ''); +INSERT INTO `ape_document` VALUES (62, '62', 1, '超级管理员', '优酷剧集获取纯php实现', 2, '/upload/image/2019-10-24/5db13ed43b192.jpg', 'article', '', 0, 0, 0, '', 1, 607, '', '', '', '', 0, '2019-10-24', 1571897127, 1580887407, 1, ''); +INSERT INTO `ape_document` VALUES (63, '63', 1, '超级管理员', 'Redis批量删除key的小技巧', 22, '/upload/image/2019-11-05/5dc0e2118ea92.jpg', 'article', '', 0, 0, 0, '', 1, 224, '', '', '', '', 0, '2019-11-05', 1572921877, 1572921893, 1, ''); +INSERT INTO `ape_document` VALUES (64, '64', 1, '超级管理员', 'composer爆错:zlib_decode():data error', 2, '/upload/image/2019-11-10/5dc822493c6cd.jpg', 'article', '', 0, 0, 0, '', 1, 122, '', '', '', '', 0, '2019-11-10', 1573397067, 1573397067, 1, ''); +INSERT INTO `ape_document` VALUES (65, '65', 1, '超级管理员', '视频完美切片存储方案 附自动化处理脚本', 2, '/upload/image/2020-01-14/5e1d7c535e272.png', 'article', '', 0, 0, 0, '', 1, 119, '', '', '', '', 0, '2020-01-14', 1578990678, 1580887385, 1, ''); +INSERT INTO `ape_document` VALUES (66, '66', 1, '超级管理员', 'PHP-全民K歌直链信息解析源码', 2, '/upload/image/2020-01-14/5e1d7d7940b97.jpg', 'article', '', 0, 0, 0, '', 1, 195, '', '', '', '', 0, '2020-01-14', 1578990972, 1580887355, 1, ''); +INSERT INTO `ape_document` VALUES (67, '67', 1, '超级管理员', '为您的网站添加MySSL安全认证签章', 22, '/upload/image/2020-01-17/5e211e3accfd3.jpg', 'article', '', 0, 0, 0, '', 1, 102, '', '', '', '', 0, '2020-01-17', 1579228733, 1579228733, 1, ''); +INSERT INTO `ape_document` VALUES (68, '68', 1, '超级管理员', 'PHP 采集专用curl函数封装', 2, '/upload/image/2020-02-01/5e353d7a370bf.png', 'article', '', 0, 0, 0, '', 1, 118, '', '', '', '', 0, '2020-02-01', 1580547452, 1580547452, 1, ''); +INSERT INTO `ape_document` VALUES (69, '69', 1, '超级管理员', '[layui] layedit如何同步编辑器内容到textarea或者form提', 23, '/upload/image/2020-03-16/5e6f20d304fab.jpg', 'article', '', 0, 0, 0, '', 1, 440, '', '', '', '', 0, '2020-03-16', 1584341204, 1584341204, 1, ''); +INSERT INTO `ape_document` VALUES (70, '70', 1, '超级管理员', '实战中如何使用Git', 2, '/upload/image/2020-03-26/5e7cb7c59c77e.jpg', 'article', '', 0, 0, 0, '', 1, 101, '', '', '', '', 0, '2020-03-26', 1585231818, 1585231873, 1, ''); +INSERT INTO `ape_document` VALUES (71, '71', 1, '超级管理员', 'Redis持久化', 22, '/upload/image/2020-03-30/5e817bf5c9bd9.jpg', 'article', '', 0, 0, 0, '', 1, 98, '', '', '', '', 0, '2020-03-30', 1585544187, 1585544187, 1, ''); +INSERT INTO `ape_document` VALUES (72, '72', 1, '超级管理员', '搭建高可用负载均衡器: haproxy+keepalived', 22, '/upload/image/2020-04-01/5e849e2352091.jpg', 'article', '', 0, 0, 0, '', 1, 133, '', '', '', '', 0, '2020-04-01', 1585749544, 1585749544, 1, ''); +INSERT INTO `ape_document` VALUES (73, '73', 1, '超级管理员', 'LVS+KeepAlived+Nginx高可用实现方案之DR模式', 22, '/upload/image/2020-04-03/5e870f5f4c02e.jpg', 'article', '', 0, 0, 0, '', 1, 110, '', '', '', '', 0, '2020-04-03', 1585909603, 1585909603, 1, ''); +INSERT INTO `ape_document` VALUES (74, '74', 1, '超级管理员', 'nginx 负载均衡的配置', 22, '/upload/image/2020-04-04/5e883ce833627.jpg', 'article', '', 0, 0, 0, '', 1, 141, '', '', '', '', 0, '2020-04-04', 1585986795, 1585986795, 1, ''); +INSERT INTO `ape_document` VALUES (75, '75', 1, '超级管理员', '哀悼抗疫英雄!网站黑白背景设置教程', 8, '/upload/image/2020-04-04/5e884ff821f2c.jpg', 'article', '', 0, 0, 0, '', 1, 232, '', '', '', '', 0, '2020-04-04', 1585991725, 1585991725, 1, ''); +INSERT INTO `ape_document` VALUES (76, '76', 1, '超级管理员', '5 分钟完成 Nginx 直播服务部署(直播 + 分流 + 画面水印)', 22, '/upload/image/2020-04-09/5e8f1aa470fd8.png', 'article', '', 0, 0, 0, '', 1, 153, '', '', '', '', 0, '2020-04-09', 1586437034, 1586438692, 1, ''); +INSERT INTO `ape_document` VALUES (77, '77', 1, '超级管理员', '让PHP程序永远在后台运行', 3, '/upload/image/2020-04-12/5e92fd04025f5.jpg', 'article', '', 0, 0, 0, '', 1, 159, '', '', '', '', 0, '2020-04-12', 1586691334, 1586691334, 1, ''); +INSERT INTO `ape_document` VALUES (78, '78', 1, '超级管理员', '图解:实战最左前缀原则', 3, '/upload/image/2020-04-14/5e9536361d1d1.jpg', 'article', '', 0, 0, 0, '', 1, 271, '', '', '', '', 0, '2020-04-14', 1586837051, 1586837051, 1, ''); +INSERT INTO `ape_document` VALUES (79, '79', 1, '超级管理员', 'upervisor做守护进程', 22, '/upload/image/2020-04-21/5e9ee94cbebc9.jpg', 'article', '', 0, 0, 0, '', 1, 256, '', '', '', '', 0, '2020-04-21', 1587472721, 1587472721, 1, ''); +INSERT INTO `ape_document` VALUES (80, '80', 1, '超级管理员', 'thinkphp mysql5.7数据迁移datetime默认值问题解决', 2, '/upload/image/2020-05-15/5ebe5915862da.jpg', 'article', '', 0, 0, 0, '', 1, 172, '', '', '', '', 0, '2020-05-15', 1589532951, 1589532964, 1, ''); +INSERT INTO `ape_document` VALUES (81, '81', 1, '超级管理员', 'PHP CURL方法封装', 3, '/upload/image/2020-07-21/5f167f41be080.jpg', 'article', '', 0, 0, 0, '', 1, 140, '', '', '', '', 0, '2020-07-21', 1595309893, 1595309893, 1, ''); +INSERT INTO `ape_document` VALUES (82, '82', 1, '超级管理员', 'git 添加密码拉去代码,免去每次输入账号密码的问题', 3, '/upload/image/2020-08-24/5f43329de5c8a.jpg', 'article', '', 0, 0, 0, '', 1, 100, '', '', '', '', 0, '2020-08-24', 1598239399, 1610954004, 1, ''); +INSERT INTO `ape_document` VALUES (83, '83', 1, '超级管理员', 'array_diff 使用栽坑记录', 30, '/upload/image/2020-08-26/5f45fa690e092.jpg', 'article', '', 0, 0, 0, '', 1, 116, '', '', '', '', 0, '2020-08-26', 1598421611, 1598421611, 1, ''); +INSERT INTO `ape_document` VALUES (84, '84', 1, '超级管理员', 'tp6 API 结合jwt自动获取user_id', 3, '/upload/image/2020-11-04/5fa2557c624e0.jpg', 'article', '', 0, 0, 0, '', 1, 58, '', '', '', '', 0, '2020-11-04', 1604474238, 1604474238, 1, ''); +INSERT INTO `ape_document` VALUES (85, '85', 1, '超级管理员', '禁止鼠标右键和禁止F12', 24, '/upload/image/2020-11-08/5fa7f3637d0aa.jpg', 'article', '', 0, 0, 0, '', 1, 53, '', '', '', '', 0, '2020-11-08', 1604842341, 1604842341, 1, ''); +INSERT INTO `ape_document` VALUES (86, '86', 1, '超级管理员', '最全的常用正则表达式大全——包括校验数字、字符、一些特殊的需求等等', 3, '/upload/image/2020-11-11/5fab93bf32d1c.jpg', 'article', '', 0, 0, 0, '', 1, 51, '', '', '', '', 0, '2020-11-11', 1605080001, 1605080001, 1, ''); +INSERT INTO `ape_document` VALUES (87, '87', 1, '超级管理员', 'PHP读取docx文档内容', 3, '/upload/image/2020-11-23/5fbb8eaa40498.png', 'article', '', 0, 0, 0, '', 1, 42, '', '', '', '', 0, '2020-11-23', 1606127420, 1606127420, 1, ''); +INSERT INTO `ape_document` VALUES (88, '88', 1, '超级管理员', 'jquery.confirm 和 modal 弹窗同时打开的bug', 24, '/upload/image/2020-11-25/5fbe1d070f48b.jpg', 'article', '', 0, 0, 0, '', 1, 41, '', '', '', '', 0, '2020-11-25', 1606294792, 1606294850, 1, ''); +INSERT INTO `ape_document` VALUES (89, '89', 1, '超级管理员', 'webuploader上传文件夹', 3, '/upload/image/2020-11-27/5fc0b4f09911e.jpg', 'article', '', 0, 0, 0, '', 1, 43, '', '', '', '', 0, '2020-11-27', 1606464753, 1606464753, 1, ''); +INSERT INTO `ape_document` VALUES (90, '90', 1, '超级管理员', 'phpspreadsheet 工具类导出整合优化,非原创', 2, '/upload/image/2020-12-11/5fd3424b71c87.jpeg', 'article', '', 0, 0, 0, '', 1, 39, '', '', '', '', 0, '2020-12-11', 1607680589, 1607680710, 1, ''); +INSERT INTO `ape_document` VALUES (91, '91', 1, '超级管理员', '解决js生成的html和原生html的样式不一致的问题', 24, '/upload/image/2020-12-15/5fd8509e9e9b8.jpeg', 'article', '', 0, 0, 0, '', 1, 37, '', '', '', '', 0, '2020-12-15', 1608011935, 1608011935, 1, ''); +INSERT INTO `ape_document` VALUES (92, '92', 1, '超级管理员', '解决 Light Year Admin 标签元素距离太近上下样式粘在一起', 3, '/upload/image/2020-12-15/5fd851f013881.jpg', 'article', '', 0, 0, 0, '', 1, 37, '', '', '', '', 0, '2020-12-15', 1608012273, 1608012273, 1, ''); +INSERT INTO `ape_document` VALUES (93, '93', 1, '超级管理员', 'jq tree_table 动态生成加载,不同的column', 24, '/upload/image/2020-12-17/5fdaebd057ca8.png', 'article', '', 0, 0, 0, '', 1, 35, '', '', '', '', 0, '2020-12-17', 1608182738, 1608182749, 1, ''); +INSERT INTO `ape_document` VALUES (94, '94', 1, '超级管理员', 'js数字格式化为千分位', 23, '/upload/image/2020-12-17/5fdafc90b349a.gif', 'article', '', 0, 0, 0, '', 1, 52, '', '', '', '', 0, '2020-12-17', 1608187026, 1608187026, 1, ''); +INSERT INTO `ape_document` VALUES (95, '95', 1, '超级管理员', 'bootstrap-table的一些操作', 3, '/upload/image/2020-12-29/5feb009c7d688.png', 'article', '', 0, 0, 0, '', 1, 42, '', '', '', '', 0, '2020-12-29', 1609236638, 1609236638, 1, ''); +INSERT INTO `ape_document` VALUES (96, '96', 1, '超级管理员', 'js 简易缓存类', 3, '/upload/image/2020-12-29/5feb01345780c.jpg', 'article', '', 0, 0, 0, '', 1, 49, '', '', '', '', 0, '2020-12-29', 1609236790, 1609236790, 1, ''); +INSERT INTO `ape_document` VALUES (97, '97', 1, '超级管理员', 'php 使用jieba分词', 2, '/upload/image/2021-01-05/5ff4138f7cb12.jpg', 'article', '', 0, 0, 0, '', 1, 51, '', '', '', '', 0, '2021-01-05', 1609831313, 1609834299, 1, ''); +INSERT INTO `ape_document` VALUES (98, '98', 1, '超级管理员', 'vue 未登录隐藏敏感信息', 23, '/upload/image/2021-01-31/601687638c5d8.png', 'article', '', 0, 0, 0, '', 1, 43, '', '', '', '', 0, '2021-01-05', 1609834231, 1612089189, 1, ''); +INSERT INTO `ape_document` VALUES (99, '99', 1, '超级管理员', '联想小新13pro更新驱动开机特别慢解决办法', 1, '/upload/image/2021-01-05/5ff436ede9f71.jpg', 'article', '', 0, 0, 0, '', 1, 45, '', '', '', '', 0, '2021-01-05', 1609840400, 1609840444, 1, ''); +INSERT INTO `ape_document` VALUES (100, '100', 1, '超级管理员', 'thinkphp6 分页加参数', 2, '/upload/image/2021-01-07/5ff72cc3698e7.png', 'article', '', 0, 0, 0, '', 1, 47, '', 'tp6 分页类使用分页实现ThinkPHP内置了分页实现,要给数据添加分页输出功能变得非常简单,可以直接在Db类查询的时候调用paginate方法:// 查询状态为1的用户数据 并且每页显示10条数据', '', '', 0, '2021-01-07', 1610034375, 1610034375, 1, ''); +INSERT INTO `ape_document` VALUES (101, '101', 1, '超级管理员', 'centos8安装elasticsearch', 22, '/upload/image/2021-01-31/601584706104c.jpg', 'article', '', 0, 0, 0, '', 1, 21, '', '', '', '', 0, '2021-01-31', 1612023058, 1612023058, 1, ''); +INSERT INTO `ape_document` VALUES (102, '102', 1, '超级管理员', 'mac 安装 hp 2132打印机驱动', 37, '/upload/image/2021-02-01/601811206abae.png', 'article', '', 0, 0, 0, '', 1, 22, '', '', '', '', 0, '2021-02-01', 1612189987, 1612245400, 1, ''); +INSERT INTO `ape_document` VALUES (103, '103', 1, '超级管理员', 'html 年-月-周 筛选视图', 31, '/upload/image/2021-02-02/601930231e83f.png', 'article', '', 0, 0, 0, '', 1, 71, '', '', '', '', 0, '2021-02-02', 1612263461, 1612263536, 1, ''); +INSERT INTO `ape_document` VALUES (104, '', 1, '超级管理员', '测试新文章', 2, '/upload/image/20220410/611aab371fb34fc01b741a46ee1a360f.jpeg', 'article', '', 0, 0, 0, '', 1, 8, '新文章', '新文章', '', '', 99, '2022-04-10', 1649556547, 1649556547, 1, ''); +INSERT INTO `ape_document` VALUES (107, '5f76511', 1, '超级管理员', '测试别名', 2, '/upload/image/20220411/9df48988fc52e476a4bc6e6c2e47987a.jpeg', 'article', '', 0, 0, 0, '', 1, 2, '', 'abstractabstractabstractabstractabstract', '', '', 99, '2022-04-11', 1649673280, 1649673280, 1, ''); +INSERT INTO `ape_document` VALUES (108, 'ceshi', 1, '超级管理员', '测试', 2, '/upload/image/20220601/35bf7a1f725be872e1dbac735f86d57e.jpg', 'article', '', 0, 0, 0, '', 1, 0, '', '2131231', '', '', 99, '2022-06-01', 1654046163, 1654046163, 1, ''); +INSERT INTO `ape_document` VALUES (109, '5b8ca4', 1, '超级管理员', '长安十二时辰11', 3, '/upload/image/20220601/0ae3eaf3371fdc892dc592a94236a8ba.jpg', 'article', '', 0, 0, 0, '', 1, 0, '', '222', '', '', 99, '2022-06-01', 1654047996, 1654047996, 1, ''); -- ---------------------------- -- Table structure for ape_document_article @@ -326,7 +433,113 @@ CREATE TABLE `ape_document_article` ( -- ---------------------------- -- Records of ape_document_article -- ---------------------------- -INSERT INTO `ape_document_article` VALUES (1, '

    源码云博客





    阿迪斯

    '); +INSERT INTO `ape_document_article` VALUES (1, '

    源码云博客

    \r\n

     

    '); +INSERT INTO `ape_document_article` VALUES (2, '

    代码如下

    支持 单一文件后缀遍历,支持所有文件遍历

        /**\r\n     * 递归获取文件列表\r\n     * @param $dir  文件地址\r\n     * @param $ext  允许文件类型 可指定查找 不设置则表示所有的\r\n     * @return array\r\n     */\r\n    public  function get_file_list($dir,$ext=\'\'){\r\n        $file_list = array();\r\n        $file_dir_list = array();\r\n        \r\n        $dir_list = scandir($dir); //查找目录  \r\n         \r\n        foreach ($dir_list as $r)\r\n        {\r\n            if ($r == \'.\' || $r == \'..\'){\r\n                continue;\r\n            }\r\n            $new_dir = $dir . \'/\' . $r;\r\n            if (is_dir($new_dir)) {\r\n                $file_dir = get_file_list($new_dir,$ext);\r\n                $file_dir_list = array_merge($file_dir_list, $file_dir);\r\n            }else{\r\n                if ($ext) {\r\n                    $pathinfo=pathinfo($new_dir);\r\n                    $ext2=$pathinfo[\'extension\'];\r\n                    if($ext2==$ext){\r\n                       $file_list[] = $new_dir;\r\n                    }\r\n                }else{\r\n                    $file_list[] = $new_dir;\r\n                }\r\n               \r\n            }\r\n        }\r\n        return array_merge($file_list, $file_dir_list);\r\n    }\r\n
    '); +INSERT INTO `ape_document_article` VALUES (3, '
     \'/(MSIE) (\\d+\\.\\d)/\',\r\n//             \'chrome\'  => \'/(Chrome)\\/(\\d+\\.\\d+)/\',\r\n//             \'firefox\' => \'/(Firefox)\\/(\\d+\\.\\d+)/\',\r\n//             \'opera\'   => \'/(Opera)\\/(\\d+\\.\\d+)/\',\r\n//             \'safari\'  => \'/Version\\/(\\d+\\.\\d+\\.\\d) (Safari)/\',\r\n//         );\r\n//         foreach($regex as $type => $reg) {\r\n//             preg_match($reg, $agent, $data);\r\n//             if(!empty($data) && is_array($data)){\r\n//                 $browser = $type === \'safari\' ? array($data[2], $data[1]) : array($data[1], $data[2]);\r\n//                 break;\r\n//             }\r\n//         }\r\n//         return empty($browser) ? false : (is_null($glue) ? $browser : implode($glue, $browser));\r\n//     }\r\n function getBrowser(){\r\n    if (strpos($_SERVER[\'HTTP_USER_AGENT\'], \'Maxthon\')) {\r\n        $browser = \'Maxthon\';\r\n    } elseif(strpos($_SERVER[\'HTTP_USER_AGENT\'], \'MSIE 12.0\')) {\r\n        $browser = \'IE12.0\';\r\n    } elseif(strpos($_SERVER[\'HTTP_USER_AGENT\'], \'MSIE 11.0\')) {\r\n        $browser = \'IE11.0\';\r\n    } elseif(strpos($_SERVER[\'HTTP_USER_AGENT\'], \'MSIE 10.0\')) {\r\n        $browser = \'IE10.0\';\r\n    } elseif(strpos($_SERVER[\'HTTP_USER_AGENT\'], \'MSIE 9.0\')) {\r\n        $browser = \'IE9.0\';\r\n    } elseif(strpos($_SERVER[\'HTTP_USER_AGENT\'], \'MSIE 8.0\')) {\r\n        $browser = \'IE8.0\';\r\n    } elseif(strpos($_SERVER[\'HTTP_USER_AGENT\'], \'MSIE 7.0\')) {\r\n        $browser = \'IE7.0\';\r\n    } elseif(strpos($_SERVER[\'HTTP_USER_AGENT\'], \'MSIE 6.0\')) {\r\n        $browser = \'IE6.0\';\r\n    } elseif(strpos($_SERVER[\'HTTP_USER_AGENT\'], \'NetCaptor\')) {\r\n        $browser = \'NetCaptor\';\r\n    } elseif(strpos($_SERVER[\'HTTP_USER_AGENT\'], \'Netscape\')) {\r\n        $browser = \'Netscape\';\r\n    } elseif(strpos($_SERVER[\'HTTP_USER_AGENT\'], \'Lynx\')) {\r\n        $browser = \'Lynx\';\r\n    } elseif(strpos($_SERVER[\'HTTP_USER_AGENT\'], \'Opera\')) {\r\n        $browser = \'Opera\';\r\n    } elseif(strpos($_SERVER[\'HTTP_USER_AGENT\'], \'Chrome\')) {\r\n        $browser = \'Chrome\';\r\n    } elseif(strpos($_SERVER[\'HTTP_USER_AGENT\'], \'Firefox\')) {\r\n        $browser = \'Firefox\';\r\n    } elseif(strpos($_SERVER[\'HTTP_USER_AGENT\'], \'Safari\')) {\r\n        $browser = \'Safari\';\r\n    } elseif(strpos($_SERVER[\'HTTP_USER_AGENT\'], \'iphone\') || strpos($_SERVER[\'HTTP_USER_AGENT\'], \'ipod\')) {\r\n        $browser = \'iphone\';\r\n    } elseif(strpos($_SERVER[\'HTTP_USER_AGENT\'], \'ipad\')) {\r\n        $browser = \'iphone\';\r\n    } elseif(strpos($_SERVER[\'HTTP_USER_AGENT\'], \'android\')) {\r\n        $browser = \'Android\';\r\n    } else {\r\n        $browser = \'other\';\r\n    }\r\n    return $browser;\r\n}\r\n   var_dump(getBrowser());\r\n?>
    '); +INSERT INTO `ape_document_article` VALUES (4, '

    代码如下


        /**\r\n     * 计算两个时间戳之?\r\n     * @param $begin_time\r\n     * @param $end_time\r\n     * @return array\r\n     */\r\n    public function timeDiff( $begin_time, $end_time ){\r\n        if ( $begin_time < $end_time ) {\r\n            $starttime = $begin_time;\r\n            $endtime = $end_time;\r\n        } else {\r\n            $starttime = $end_time;\r\n            $endtime = $begin_time;\r\n        }\r\n        $timediff = $endtime - $starttime;\r\n        $days = intval( $timediff / 86400 );\r\n        $remain = $timediff % 86400;\r\n        $hours = intval( $remain / 3600 );\r\n        $remain = $remain % 3600;\r\n        $mins = intval( $remain / 60 );\r\n        $secs = $remain % 60;\r\n        $res = array( \"day\" => $days, \"hour\" => $hours, \"min\" => $mins, \"sec\" => $secs );\r\n        return $res;\r\n    }
    '); +INSERT INTO `ape_document_article` VALUES (5, '

    原命令

    yum install rrdtool rrdtool-devel rrdtool-php rrdtool-perl

    例如:php5.6 则命令修改为


    yum install rrdtool rrdtool-devel rrdtool-php56w rrdtool-perl


    就是在  php后面加上版本号  

    '); +INSERT INTO `ape_document_article` VALUES (6, '
     \r\n\r\n$config[\'sess_driver\'] = \'files\';\r\n$config[\'sess_cookie_name\'] = \'ci_session\';\r\n$config[\'sess_expiration\'] = 7200;\r\n$config[\'sess_save_path\'] =  APPPATH.\'system\\session\';\r\n$config[\'sess_match_ip\'] = FALSE;\r\n$config[\'sess_time_to_update\'] = 300;\r\n$config[\'sess_regenerate_destroy\'] = FALSE;\r\n\r\n


    COOKIE

    $config[\'cookie_prefix\']        = \'ipms_\';

    $config[\'cookie_domain\']        = \'\';

    $config[\'cookie_path\']          = \'/\';

    $config[\'cookie_secure\']        = FALSE;

    $config[\'cookie_httponly\']      = FALSE;

    '); +INSERT INTO `ape_document_article` VALUES (7, '

    thinkphp 登录验证 或者其他跳转使用  iframe类框架  跳转出现 跳转内容出现在iframe框架内的问题解决

    注意首页的坑

    	protected function _initialize(){\r\n		//如果两个cookie有一个不存在,则返回false\r\n		if(!isset($_SESSION[\'username\'])) {\r\n			  //检测是否登录,若没登录则转向登录界面\r\n			 // header(\'Location:\'.U(\'Login/login\'));\r\n				// $this->redirect(\'Login/login\');\r\n			$url=U(\'Login/login\');\r\n			 echo (\'<script>top.location.href=\"\'.$url.\'\";</script>\');\r\n			 exit;\r\n		}\r\n	}
    '); +INSERT INTO `ape_document_article` VALUES (8, '

    源地址  http://www.win-ui.com/winadmin/index.html

    基于Layui的前端模板,快速打造Win10风格Web前端

    基于json  设置

    winui.js 桌面等控制 

    login.js  登录控制  

    \"QQ图片20171117112812.png\"


    源代码原作者已经开源

    开源地址 :https://github.com/Leo0216/winadmin

    '); +INSERT INTO `ape_document_article` VALUES (9, '
    <?php\r\nclass redisSession{\r\n    /**\r\n     * 保存session的数据库表的信息\r\n     */\r\n    private $_options = array(\r\n        \'handler\' => null, //数据库连接句柄\r\n        \'host\' => null,\r\n        \'port\' => null,\r\n        \'lifeTime\' => null,\r\n        \'prefix\'   => \'PHPREDIS_SESSION:\'\r\n    );\r\n\r\n    /**\r\n     * 构造函数\r\n     * @param $options 设置信息数组\r\n     */\r\n    public function __construct($options=array()){\r\n        if(!class_exists(\"redis\", false)){\r\n            die(\"必须安装redis扩展\");\r\n        }\r\n        if(!isset($options[\'lifeTime\']) || $options[\'lifeTime\'] <= 0){\r\n            $options[\'lifeTime\'] = ini_get(\'session.gc_maxlifetime\');\r\n        }\r\n        $this->_options = array_merge($this->_options, $options);\r\n    }\r\n\r\n    /**\r\n     * 开始使用该驱动的session\r\n     */\r\n    public function begin(){\r\n        if($this->_options[\'host\'] === null ||\r\n           $this->_options[\'port\'] === null ||\r\n           $this->_options[\'lifeTime\'] === null\r\n        ){\r\n            return false;\r\n        }\r\n        //设置session处理函数\r\n        session_set_save_handler(\r\n            array($this, \'open\'),\r\n            array($this, \'close\'),\r\n            array($this, \'read\'),\r\n            array($this, \'write\'),\r\n            array($this, \'destory\'),\r\n            array($this, \'gc\')\r\n        );\r\n    }\r\n    /**\r\n     * 自动开始回话或者session_start()开始回话后第一个调用的函数\r\n     * 类似于构造函数的作用\r\n     * @param $savePath 默认的保存路径\r\n     * @param $sessionName 默认的参数名,PHPSESSID\r\n     */\r\n    public function open($savePath, $sessionName){\r\n        if(is_resource($this->_options[\'handler\'])) return true;\r\n        //连接redis\r\n        $redisHandle = new Redis();\r\n        $redisHandle->connect($this->_options[\'host\'], $this->_options[\'port\']);\r\n        if(!$redisHandle){\r\n            return false;\r\n        }\r\n\r\n        $this->_options[\'handler\'] = $redisHandle;\r\n//        $this->gc(null);\r\n        return true;\r\n\r\n    }\r\n\r\n    /**\r\n     * 类似于析构函数,在write之后调用或者session_write_close()函数之后调用\r\n     */\r\n    public function close(){\r\n        return $this->_options[\'handler\']->close();\r\n    }\r\n\r\n    /**\r\n     * 读取session信息\r\n     * @param $sessionId 通过该Id唯一确定对应的session数据\r\n     * @return session信息/空串\r\n     */\r\n    public function read($sessionId){\r\n        $sessionId = $this->_options[\'prefix\'].$sessionId; \r\n        return $this->_options[\'handler\']->get($sessionId);\r\n    }\r\n\r\n    /**\r\n     * 写入或者修改session数据\r\n     * @param $sessionId 要写入数据的session对应的id\r\n     * @param $sessionData 要写入的数据,已经序列化过了\r\n     */\r\n    public function write($sessionId, $sessionData){\r\n        $sessionId = $this->_options[\'prefix\'].$sessionId; \r\n        return $this->_options[\'handler\']->setex($sessionId, $this->_options[\'lifeTime\'], $sessionData);\r\n    }\r\n\r\n    /**\r\n     * 主动销毁session会话\r\n     * @param $sessionId 要销毁的会话的唯一id\r\n     */\r\n    public function destory($sessionId){\r\n        $sessionId = $this->_options[\'prefix\'].$sessionId; \r\n//        $array = $this->print_stack_trace();\r\n//        log::write($array);\r\n        return $this->_options[\'handler\']->delete($sessionId) >= 1 ? true : false;\r\n    }\r\n\r\n    /**\r\n     * 清理绘画中的过期数据\r\n     * @param 有效期\r\n     */\r\n    public function gc($lifeTime){\r\n        //获取所有sessionid,让过期的释放掉\r\n        //$this->_options[\'handler\']->keys(\"*\");\r\n        return true;\r\n    }\r\n    //打印堆栈信息\r\n    public function print_stack_trace()\r\n    {\r\n        $array = debug_backtrace ();\r\n        //截取用户信息\r\n        $var = $this->read(session_id());\r\n        $s = strpos($var, \"index_dk_user|\");\r\n        $e = strpos($var, \"}authId|\");\r\n        $user = substr($var,$s+14,$e-13);\r\n        $user = unserialize($user);\r\n        //print_r($array);//信息很齐全\r\n        unset ( $array [0] );\r\n        if(!empty($user)){\r\n          $traceInfo = $user[\'id\'].\'|\'.$user[\'user_name\'].\'|\'.$user[\'user_phone\'].\'|\'.$user[\'presona_name\'].\'++++++++++++++++\\n\';\r\n        }else{\r\n          $traceInfo = \'++++++++++++++++\\n\';\r\n        }\r\n        $time = date ( \"y-m-d H:i:m\" );\r\n        foreach ( $array as $t ) {\r\n            $traceInfo .= \'[\' . $time . \'] \' . $t [\'file\'] . \' (\' . $t [\'line\'] . \') \';\r\n            $traceInfo .= $t [\'class\'] . $t [\'type\'] . $t [\'function\'] . \'(\';\r\n            $traceInfo .= implode ( \', \', $t [\'args\'] );\r\n            $traceInfo .= \")\\n\";\r\n        }\r\n        $traceInfo .= \'++++++++++++++++\';\r\n        return $traceInfo;\r\n    }\r\n\r\n}\r\n\r\n\r\n//入口处调用\r\n$handler = new redisSession(array(\r\n                \'host\' => \"127.0.0.1\",\r\n                \'port\' => \"6379\"\r\n        ));\r\n$handler->begin();
    '); +INSERT INTO `ape_document_article` VALUES (10, '

    在登录时  首页尤其需要注意

        public function __construct() {  \r\n        parent::__construct ();\r\n        error_reporting(E_ALL^E_NOTICE);\r\n        $this->load->helper(array(  \r\n                \'form\',  \r\n                \'url\'   \r\n        ));  \r\n        if (!$this->session->userdata(\'username\')) {\r\n            $url=(site_url(\'login/login\'));//获取登录地址  避免首页登录出现问题\r\n             echo(\'\');\r\n        	 die();\r\n        }\r\n    }  
    '); +INSERT INTO `ape_document_article` VALUES (11, '

    首页php教程> 正文

    php 调用ffmpeg获取视频信息的方法

    作者: default|标签:ffmpeg PHP 信息|2017-7-12 10:40

    FFmpeg是一套可以用来记录、转换数字音频、视频,并能将其转化为流的开源计算机程序。采用LGPL或GPL许可证。它提供了录制、转换以及流化音视频的完整解决方案。它包含了非常先进的音频/视频编解码库libavcodec,为了保证高可移植性和编解码质量,libavcodec里很多code都是从头开发的。

    本文将介绍使用php调用ffmpeg获取视频信息,调用ffmpeg首先需要服务器上安装了ffmpeg,安装方法很简单,可自行搜索。

    代码如下:

    <?php\r\n// 定义ffmpeg路径及命令常量\r\ndefine(\'FFMPEG_CMD\', \'/usr/local/bin/ffmpeg -i \"%s\" 2>&1\');\r\n \r\n/**\r\n * 使用ffmpeg获取视频信息\r\n * @param String $file 视频文件\r\n * @return Array\r\n */\r\nfunction getVideoInfo($file){\r\n ob_start();\r\n passthru(sprintf(FFMPEG_CMD, $file));\r\n $video_info = ob_get_contents();\r\n ob_end_clean();\r\n \r\n // 使用输出缓冲,获取ffmpeg所有输出内容\r\n $ret = array();\r\n \r\n // Duration: 00:33:42.64, start: 0.000000, bitrate: 152 kb/s\r\n if (preg_match(\"/Duration: (.*?), start: (.*?), bitrate: (\\d*) kb\\/s/\", $video_info, $matches)){\r\n  $ret[\'duration\'] = $matches[1]; // 视频长度\r\n  $duration = explode(\':\', $matches[1]);\r\n  $ret[\'seconds\'] = $duration[0]*3600 + $duration[1]*60 + $duration[2]; // 转为秒数\r\n  $ret[\'start\'] = $matches[2]; // 开始时间\r\n  $ret[\'bitrate\'] = $matches[3]; // bitrate 码率 单位kb\r\n }\r\n \r\n // Stream #0:1: Video: rv20 (RV20 / 0x30325652), yuv420p, 352x288, 117 kb/s, 15 fps, 15 tbr, 1k tbn, 1k tbc\r\n if(preg_match(\"/Video: (.*?), (.*?), (.*?)[,\\s]/\", $video_info, $matches)){\r\n  $ret[\'vcodec\'] = $matches[1];  // 编码格式\r\n  $ret[\'vformat\'] = $matches[2]; // 视频格式\r\n  $ret[\'resolution\'] = $matches[3]; // 分辨率\r\n  list($width, $height) = explode(\'x\', $matches[3]);\r\n  $ret[\'width\'] = $width;\r\n  $ret[\'height\'] = $height;\r\n }\r\n \r\n // Stream #0:0: Audio: cook (cook / 0x6B6F6F63), 22050 Hz, stereo, fltp, 32 kb/s\r\n if(preg_match(\"/Audio: (.*), (\\d*) Hz/\", $video_info, $matches)){\r\n  $ret[\'acodec\'] = $matches[1];  // 音频编码\r\n  $ret[\'asamplerate\'] = $matches[2]; // 音频采样频率\r\n }\r\n \r\n if(isset($ret[\'seconds\']) && isset($ret[\'start\'])){\r\n  $ret[\'play_time\'] = $ret[\'seconds\'] + $ret[\'start\']; // 实际播放时间\r\n }\r\n \r\n $ret[\'size\'] = filesize($file); // 视频文件大小\r\n $video_info = iconv(\'gbk\',\'utf8\', $video_info);\r\n return array($ret, $video_info);\r\n \r\n}\r\n \r\n// 输出视频信息\r\n$video_info = getVideoInfo(\'myvideo.avi\');\r\nprint_r($video_info[0]);\r\n?>


    输出

    Array\r\n(\r\n [duration] => 00:33:42.64\r\n [seconds] => 2022.64\r\n [start] => 0.000000\r\n [bitrate] => 152\r\n [vcodec] => rv20 (RV20 / 0x30325652)\r\n [vformat] => yuv420p\r\n [resolution] => 352x288\r\n [width] => 352\r\n [height] => 288\r\n [acodec] => cook (cook / 0x6B6F6F63)\r\n [asamplerate] => 22050\r\n [play_time] => 2022.64\r\n [size] => 38630744\r\n)
    '); +INSERT INTO `ape_document_article` VALUES (12, '

    如果你是 Debian/Ubuntu 的话请在终端输入:

    apt-get install nginx\r\n

    CentOS

    yum install nginx\r\n

    修改配置:
    然后, 找到你的 Nginx 配置文件添加虚拟机

    server    {\r\n        listen          80;\r\n        server_name     abc.com;#你的网站\r\n        location / {\r\n                proxy_set_header Accept-Encoding \"\";\r\n                proxy_pass             http://efg.com/;#你要反代的网站\r\n                proxy_redirect          off;\r\n                proxy_set_header        X-Real-IP       $remote_addr;\r\n                proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;\r\n                sub_filter  \'abc.com\' \'efg.com\';#替换其中所有的原网站链接\r\n                sub_filter_types *;\r\n                sub_filter_once off;\r\n\r\n        }\r\n    }\r\n

    重启服务:

     service nginx restart\r\n

    显示 OK 成功即可

    '); +INSERT INTO `ape_document_article` VALUES (13, '

    抽取音频命令
    ffmpeg -i 3.mp4 -vn -y -acodec copy 3.aac
    ffmpeg -i 3.mp4 -vn -y -acodec copy 3.m4a


     提取视频 (Extract Video)
    ffmpeg -i Life.of.Pi.has.subtitles.mkv -vcodec copy –an  videoNoAudioSubtitle.mp4




    音视频合成命令
    ffmpeg -i video2.avi -i audio.mp3 -vcodec copy -acodec copy output.avi


    查看音视频文件信息命令
    ffmpeg -i 3.mp4
    ffmpeg -i 3.aac
    ffmpeg -i 3.m4a

    '); +INSERT INTO `ape_document_article` VALUES (14, '

    在服务端  执行命令

    vi /etc/exports

    修改配置文件为

    /mnt/cephfs 192.168.192.0/8(rw,no_root_squash,async)

    既: 加入 no_root_squash



    详细描述:

    在客户机通过

    mount -o rw -t nfs 192.168.192.204:/mnt/cephfs /mnt/nfs

    命令将网络文件mount到本地。执行完成之后,目录是可以访问了,但无法写入。

    原因:
    发现exports目录权限中,参数no_root_squash的其作用是:登入 NFS 主机使用分享目录的使用者,如果是root 的话,那么对于export目录来说,它就具有root的权限!
    默认情况使用的是相反参数root_squash:在登入 NFS 主机export目录的使用者如果当root时,那么这个使用者的权限将被压缩成为匿名使用者,通常他的                      UID 与 GID 都会变成 nobody 那个身份。
    因为客户端是使用root登录的,自然权限被压缩为nobody了,难怪无法写入。将配置信息改为:
    /mnt/cephfs 192.168.192.0/8(rw,no_root_squash)
    据说有点不安全,但问题是解决了。 

    '); +INSERT INTO `ape_document_article` VALUES (15, '

    碰到 input但是内容部想让修改

    类似这样\"QQ图片20171225182708.png\"

    修改input成 <label class=\"layui-input\">xxx</label>  这样即可

    '); +INSERT INTO `ape_document_article` VALUES (16, '

    \"image\"

    FFmpeg 常用命令DEMO

    \":feet:\"常用

    \":bouquet:\"视频

    \":cherry_blossom:\" 音频

    \":tulip:\"复合流

    \":four_leaf_clover:\"摄像头

    \":rose:\"图片流

    \":sunflower:\"RTSP

    \":hibiscus:\"网络流和本地流切换

    '); +INSERT INTO `ape_document_article` VALUES (17, '

    composer安装出现  ext 目录无法找到以及 php_bz2.dll 拓展无法找到解决办法

    找到 php.ini 该版本对应的  

    查找  extension_dir

    将 extension_dir= 后面的值改成windows的路径补全即类似这种  

    extension_dir =\"E:\\xampp\\php\\ext\"  即可解决

    '); +INSERT INTO `ape_document_article` VALUES (18, '

    该界面是用来测试Apache服务器是否工作正常。

    禁用该测试页面的方法如下:

    1.打开终端,登陆到CentOS上

    2.在终端中输入以下命令

    cd /etc/httpd/conf.d\r\n

    3.继续输入命令,显示当前目录下的文件

    ls\r\n

    4.找到名为welcome.conf的文件,并用vim打开

    vim welcome.conf\r\n

    welcome.conf的内容如下

    # \r\n# This configuration file enables the default \"Welcome\"\r\n# page if there is no default index page present for\r\n# the root URL.  To disable the Welcome page, comment\r\n# out all the lines below.\r\n#\r\n<LocationMatch \"^/+$\">\r\n    Options -Indexes\r\n    ErrorDocument 403 /error/noindex.html\r\n</LocationMatch>\r\n

    文件中的说明性内容说明了该文件的主要作用,以及关闭该作用的方法。其实该文件也是一个普通的配置文件,并被包含进了Apache服务器httpd.conf主文件中,只要用\"#\"将welcome.conf的内容注释掉即可,如下:

    # \r\n# This configuration file enables the default \"Welcome\"\r\n# page if there is no default index page present for\r\n# the root URL.  To disable the Welcome page, comment\r\n# out all the lines below.\r\n#\r\n#<LocationMatch \"^/+$\">\r\n#    Options -Indexes\r\n#    ErrorDocument 403 /error/noindex.html\r\n#</LocationMatch>\r\n

    5.重新启动Apache

    service httpd restart\r\n

    :查看noindex.html为存放路劲

    cd /var/www/error/\r\nls
    '); +INSERT INTO `ape_document_article` VALUES (19, '

    编辑一下CentOS的: /etc/ssh/sshd_config 

    #TCPKeepAlive yes    \r\n#ClientAliveInterval 0   

    去掉前面的#号,并将0改为3 

    然后重启service sshd restart 

    '); +INSERT INTO `ape_document_article` VALUES (20, '

    js作用域

    先在函数体内部查找,查找不到向上查找,向上找不到再向上知道 全局windows为止

    \"无标题.jpg\"

    var 作用声明变量 不加var 单纯赋值  如果这个变量没有声明则向上查找

    '); +INSERT INTO `ape_document_article` VALUES (21, '

    视频转码

    ffmpeg -i test.mp4 -c:v libx264 -strict -2 1.mp4

    视频转为一个低质量的预览文件

    ffmpeg -i test.mp4 -c:v libx264 -vf \'scale=480:trunc(ow/a/2)*2\' -crf 30 -profile:v baseline -strict -2 1.mp4

    音频转MP4,单声音

    ffmpeg -i test.mp4 -vn -strict -2 1.mp4

    以及常见命令

    【FFmpeg】FFmpeg常用基本命令

    1.分离视频音频流

    ffmpeg -i input_file -vcodec copy -an output_file_video  //分离视频流\r\nffmpeg -i input_file -acodec copy -vn output_file_audio  //分离音频流

    2.视频解复用

    ffmpeg –i test.mp4 –vcodec copy –an –f m4v test.264\r\nffmpeg –i test.avi –vcodec copy –an –f m4v test.264

    3.视频转码

    ffmpeg –i test.mp4 –vcodec h264 –s 352*278 –an –f m4v test.264              //转码为码流原始文件\r\nffmpeg –i test.mp4 –vcodec h264 –bf 0 –g 25 –s 352*278 –an –f m4v test.264  //转码为码流原始文件\r\nffmpeg –i test.avi -vcodec mpeg4 –vtag xvid –qsame test_xvid.avi            //转码为封装文件\r\n//-bf B帧数目控制,-g 关键帧间隔控制,-s 分辨率控制

    4.视频封装

    ffmpeg –i video_file –i audio_file –vcodec copy –acodec copy output_file

    5.视频剪切

    ffmpeg –i test.avi –r 1 –f image2 image-%3d.jpeg        //提取图片\r\nffmpeg -ss 0:1:30 -t 0:0:20 -i input.avi -vcodec copy -acodec copy output.avi    //剪切视频\r\n//-r 提取图像的频率,-ss 开始时间,-t 持续时间

    6.视频录制

    ffmpeg –i rtsp://192.168.3.205:5555/test –vcodec copy out.avi

    7.YUV序列播放

    ffplay -f rawvideo -video_size 1920x1080 input.yuv

    8.YUV序列转AVI

    ffmpeg –s w*h –pix_fmt yuv420p –i input.yuv –vcodec mpeg4 output.avi

    9.视频切片

    主要把视频源切成若干个.ts格式的视频片段然后生成一个.m3u8的切片文件索引提供给html5的video做hls直播源

    ffmpeg -i 视频源地址 -strict -2 -c:v libx264 -c:a aac -f hls m3u8文件输出地址

    常用参数说明:

    主要参数:
    -i 设定输入流
    -f 设定输出格式
    -ss 开始时间
    视频参数:
    -b 设定视频流量,默认为200Kbit/s
    -r 设定帧速率,默认为25
    -s 设定画面的宽与高
    -aspect 设定画面的比例
    -vn 不处理视频
    -vcodec 设定视频编解码器,未设定时则使用与输入流相同的编解码器
    音频参数:
    -ar 设定采样率
    -ac 设定声音的Channel数
    -acodec 设定声音编解码器,未设定时则使用与输入流相同的编解码器
    -an 不处理音频


    其他命令


    如此强大的FFmpeg,能够实现视频采集、视频格式转化、视频截图、视频添加水印、视频切片、视频录制、视频推流、更改音视频参数功能等。通过终端命令如何实现这些功能,Richy在本文做一记录,以备之后查阅。

    注意:下面一一列举的命令,未归类整理,命令参数供参考。

    如果参数有误,大家可对照文章-FFmpeg参数命令,进行修改。

    第一组

    1.分离视频音频流

    ffmpeg -i input_file -vcodec copy -an output_file_video  //分离视频流ffmpeg -i input_file -acodec copy -vn output_file_audio  //分离音频流

    2.视频解复用

    ffmpeg –i test.mp4 –vcodec copy –an –f m4v test.264

    ffmpeg –i test.avi –vcodec copy –an –f m4v test.264

    3.视频转码

    ffmpeg –i test.mp4 –vcodec h264 –s 352*278 –an –f m4v test.264

    //转码为码流原始文件

    ffmpeg –i test.mp4 –vcodec h264 –bf 0 –g 25 –s 352*278 –an –f m4v test.264 //转码为码流原始文件

    ffmpeg –i test.avi -vcodec mpeg4 –vtag xvid –qsame test_xvid.avi //转码为封装文件

    说明:-bf B帧数目控制,-g 关键帧间隔控制,-s 分辨率控制

    4.视频封装

    ffmpeg –i video_file –i audio_file –vcodec copy –acodec copy output_file

    5.视频剪切

    ffmpeg –i test.avi –r 1 –f image2 image-%3d.jpeg //提取图片

    ffmpeg -ss 0:1:30 -t 0:0:20 -i input.avi -vcodec copy -acodec copy output.avi //剪切视频//-r 提取图像的频率,-ss 开始时间,-t 持续时间

    6.视频录制

    ffmpeg –i rtsp://192.168.3.205:5555/test –vcodec copy out.avi

    7、利用ffmpeg视频切片

    主要把视频源切成若干个.ts格式的视频片段然后生成一个.m3u8的切片文件索引提供给html5的video做hls直播源

    命令如下:

    ffmpeg -i 视频源地址 -strict -2 -c:v libx264 -c:a aac -f hls m3u8文件输出地址

    8、ffmpeg缩放视频

    假设原始视频尺寸是 1080p(即 1920×1080 px,16:9),使用下面命令可以缩小到 480p:

    命令如下:

    ffmpeg -i 视频源地址 -vf scale=853:480 -acodec aac -vcodec h264 视频输出地址(如:out.mp4)

    各个参数的含义:-i a.mov 指定待处理视频的文件名-vf scale=853:480 vf 参数用于指定视频滤镜,其中 scale 表示缩放,后面的数字表示缩放至 853×480 px,其中的 853px 是计算而得,因为原始视频的宽高比为 16:9,所以为了让目标视频的高度为 480px,则宽度 = 480 x 9 / 16 = 853-acodec aac 指定音频使用 aac 编码。注:因为 ffmpeg 的内置 aac 编码目前(写这篇文章时)还是试验阶段,故会提示添加参数 “-strict -2” 才能继续,尽管添加即可。又或者使用外部的 libfaac(需要重新编译 ffmpeg)。-vcodec h264 指定视频使用 h264 编码。注:目前手机一般视频拍摄的格式(封装格式、文件格式)为 mov 或者 mp4,这两者的音频编码都是 aac,视频都是 h264。out.mp4 指定输出文件名上面的参数 scale=853:480 当中的宽度和高度实际应用场景中通常只需指定一个,比如指定高度为 480 或者 720,至于宽度则可以传入 “-1” 表示由原始视频的宽高比自动计算而得。即参数可以写为:scale=-1:480,当然也可以 scale=480:-1

    9、ffmpeg裁剪

    有时可能只需要视频的正中一块,而两头的内容不需要,这时可以对视频进行裁剪(crop),比如有一个竖向的视频 1080 x 1920,如果指向保留中间 1080×1080 部分命令如下:ffmpeg -i 视频源地址 -strict -2 -vf crop=1080:1080:0:420 视频输出地址(如:out.mp4)

    其中的 crop=1080:1080:0:420 才裁剪参数,具体含义是 crop=width:height:x:y,其中 width 和 height 表示裁剪后的尺寸,x:y 表示裁剪区域的左上角坐标。比如当前这个示例,我们只需要保留竖向视频的中间部分,所以 x 不用偏移,故传入0,而 y 则需要向下偏移:(1920 – 1080) / 2 = 420

    10. 转视频格式

    ffmpeng -i source.mp4 -c:v libx264 -crf 24 destination.flv

    其中 -crf 很重要,是控制转码后视频的质量,质量越高,文件也就越大。

    此值的范围是 0 到 51:0 表示高清无损;23 是默认值(如果没有指定此参数);51 虽然文件最小,但效果是最差的。

    值越小,质量越高,但文件也越大,建议的值范围是 18 到 28。而值 18 是视觉上看起来无损或接近无损的,当然不代表是数据(技术上)的转码无损。

    第二组

    1.ffmpeg 把文件当做直播推送至服务器 (RTMP + FLV)

    ffmpeg - re -i demo.mp4 -c copy - f flv rtmp://w.gslb.letv/live/streamid

    2.将直播的媒体保存到本地

    ffmpeg -i rtmp://r.glsb.letv/live/streamid -c copy streamfile.flv

    3.将一个直播流,视频改用h264压缩,音频改用faac压缩,送至另一个直播服务器

    ffmpeg -i rtmp://r.glsb.letv/live/streamidA -c:a libfaac -ar 44100 -ab 48k -c:v libx264 -vpre slow -vpre baseline -f flv rtmp://w.glsb.letv/live/streamb

    4.提取视频中的音频,并保存为mp3 然后输出

    ffmpeg -i input.avi -b:a 128k output.mp3

    第三组

    1.获取视频的信息

    ffmpeg -i video.avi

    2.将图片序列合成视频

    ffmpeg -f image2 -i image%d.jpg video.mpg

    上面的命令会把当前目录下的图片(名字如:image1.jpg. image2.jpg. 等...)合并成video.mpg

    3.将视频分解成图片序列

    ffmpeg -i video.mpg image%d.jpg

    上面的命令会生成image1.jpg. image2.jpg. ...

    支持的图片格式有:PGM. PPM. PAM. PGMYUV. JPEG. GIF. PNG. TIFF. SGI

    4.为视频重新编码以适合在iPod/iPhone上播放

    ffmpeg -i source_video.avi input -acodec aac -ab 128kb -vcodec mpeg4 -b 1200kb -mbd 2 -flags +4mv+trell -aic 2 -cmp 2 -subcmp 2 -s 320x180 -title X final_video.mp4

    5.为视频重新编码以适合在PSP上播放

    ffmpeg -i source_video.avi -b 300 -s 320x240 -vcodec xvid -ab 32 -ar 24000 -acodec aac final_video.mp4

    6.从视频抽出声音.并存为Mp3

    ffmpeg -i source_video.avi -vn -ar 44100 -ac 2 -ab 192 -f mp3 sound.mp3

    7.将wav文件转成Mp3

    ffmpeg -i son_origine.avi -vn -ar 44100 -ac 2 -ab 192 -f mp3 son_final.mp3

    8.将.avi视频转成.mpg

    ffmpeg -i video_origine.avi video_finale.mpg

    9.将.mpg转成.avi

    ffmpeg -i video_origine.mpg video_finale.avi

    10.将.avi转成gif动画(未压缩)

    ffmpeg -i video_origine.avi gif_anime.gif

    11.合成视频和音频

    ffmpeg -i son.wav -i video_origine.avi video_finale.mpg

    12.将.avi转成.flv

    ffmpeg -i video_origine.avi -ab 56 -ar 44100 -b 200 -r 15 -s 320x240 -f flv video_finale.flv

    13.将.avi转成dv

    ffmpeg -i video_origine.avi -s pal -r pal -aspect 4:3 -ar 48000 -ac 2 video_finale.dv

    或者:

    ffmpeg -i video_origine.avi -target pal-dv video_finale.dv

    14.将.avi压缩成divx

    ffmpeg -i video_origine.avi -s 320x240 -vcodec msmpeg4v2 video_finale.avi

    15.将Ogg Theora压缩成Mpeg dvd

    ffmpeg -i film_sortie_cinelerra.ogm -s 720x576 -vcodec mpeg2video -acodec mp3 film_terminate.mpg

    16.将.avi压缩成SVCD mpeg2

    NTSC格式:

    ffmpeg -i video_origine.avi -target ntsc-svcd video_finale.mpg

    PAL格式:

    ffmpeg -i video_origine.avi -target pal-dvcd video_finale.mpg

    17.将.avi压缩成VCD mpeg2

    NTSC格式:

    ffmpeg -i video_origine.avi -target ntsc-vcd video_finale.mpg

    PAL格式:

    ffmpeg -i video_origine.avi -target pal-vcd video_finale.mpg

    18.多通道编码

    ffmpeg -i fichierentree -pass 2 -passlogfile ffmpeg2pass fichiersortie-2

    19.从flv提取mp3

    ffmpeg -i source.flv -ab 128k dest.mp3

    第四组

    1、将文件当做直播送至live

    ffmpeg -re -i localFile.mp4 -c copy -f flv rtmp://server/live/streamName

    2、将直播媒体保存至本地文件

    ffmpeg -i rtmp://server/live/streamName -c copy dump.flv

    3、将其中一个直播流,视频改用h264压缩,音频不变,送至另外一个直播服务流

    ffmpeg -i rtmp://server/live/originalStream -c:a copy -c:v libx264 -vpre slow -f flv rtmp://server/live/h264Stream

    4、将其中一个直播流,视频改用h264压缩,音频改用faac压缩,送至另外一个直播服务流

    ffmpeg -i rtmp://server/live/originalStream -c:a libfaac -ar 44100 -ab 48k -c:v libx264 -vpre slow -vpre baseline -f flv rtmp://server/live/h264Stream

    5、将其中一个直播流,视频不变,音频改用faac压缩,送至另外一个直播服务流

    ffmpeg -i rtmp://server/live/originalStream -acodec libfaac -ar 44100 -ab 48k -vcodec copy -f flv rtmp://server/live/h264_AAC_Stream

    6、将一个高清流,复制为几个不同视频清晰度的流重新发布,其中音频不变

    ffmpeg -re -i rtmp://server/live/high_FMLE_stream -acodec copy -vcodec x264lib -s 640×360 -b 500k -vpre medium -vpre baseline rtmp://server/live/baseline_500k -acodec copy -vcodec x264lib -s 480×272 -b 300k -vpre medium -vpre baseline rtmp://server/live/baseline_300k -acodec copy -vcodec x264lib -s 320×200 -b 150k -vpre medium -vpre baseline rtmp://server/live/baseline_150k -acodec libfaac -vn -ab 48k rtmp://server/live/audio_only_AAC_48k

    7、功能一样,只是采用-x264opts选项

    ffmpeg -re -i rtmp://server/live/high_FMLE_stream -c:a copy -c:v x264lib -s 640×360 -x264opts bitrate=500:profile=baseline:preset=slow rtmp://server/live/baseline_500k -c:a copy -c:v x264lib -s 480×272 -x264opts bitrate=300:profile=baseline:preset=slow rtmp://server/live/baseline_300k -c:a copy -c:v x264lib -s 320×200 -x264opts bitrate=150:profile=baseline:preset=slow rtmp://server/live/baseline_150k -c:a libfaac -vn -b:a 48k rtmp://server/live/audio_only_AAC_48k

    8、将当前摄像头及音频通过DSSHOW采集,视频h264、音频faac压缩后发布

    ffmpeg -r 25 -f dshow -s 640×480 -i video=”video source name”:audio=”audio source name” -vcodec libx264 -b 600k -vpre slow -acodec libfaac -ab 128k -f flv rtmp://server/application/stream_name

    9、将一个JPG图片经过h264压缩循环输出为mp4视频

    ffmpeg.exe -i INPUT.jpg -an -vcodec libx264 -coder 1 -flags +loop -cmp +chroma -subq 10 -qcomp 0.6 -qmin 10 -qmax 51 -qdiff 4 -flags2 +dct8x8 -trellis 2 -partitions +parti8x8+parti4x4 -crf 24 -threads 0 -r 25 -g 25 -y OUTPUT.mp4

    10、将普通流视频改用h264压缩,音频不变,送至高清流服务(新版本FMS live=1)

    ffmpeg -i rtmp://server/live/originalStream -c:a copy -c:v libx264 -vpre slow -f flv “rtmp://server/live/h264Stream live=1〃

    '); +INSERT INTO `ape_document_article` VALUES (22, '

    php支持断点续传的文件下载类

    下载类

    <?php\r\n/** php下载类,支持断点续传\r\n*   Date:   2013-06-30\r\n*   Author: fdipzone\r\n*   Ver:    1.0\r\n*\r\n*   Func:\r\n*   download: 下载文件\r\n*   setSpeed: 设置下载速度\r\n*   getRange: 获取header中Range\r\n*/\r\n\r\nclass FileDownload{ // class start\r\n\r\n    private $_speed = 512;   // 下载速度\r\n\r\n\r\n    /** 下载\r\n    * @param String  $file   要下载的文件路径\r\n    * @param String  $name   文件名称,为空则与下载的文件名称一样\r\n    * @param boolean $reload 是否开启断点续传\r\n    */\r\n    public function download($file, $name=\'\', $reload=false){\r\n        if(file_exists($file)){\r\n            if($name==\'\'){\r\n                $name = basename($file);\r\n            }\r\n\r\n            $fp = fopen($file, \'rb\');\r\n            $file_size = filesize($file);\r\n            $ranges = $this->getRange($file_size);\r\n\r\n            header(\'cache-control:public\');\r\n            header(\'content-type:application/octet-stream\');\r\n            header(\'content-disposition:attachment; filename=\'.$name);\r\n\r\n            if($reload && $ranges!=null){ // 使用续传\r\n                header(\'HTTP/1.1 206 Partial Content\');\r\n                header(\'Accept-Ranges:bytes\');\r\n                \r\n                // 剩余长度\r\n                header(sprintf(\'content-length:%u\',$ranges[\'end\']-$ranges[\'start\']));\r\n                \r\n                // range信息\r\n                header(sprintf(\'content-range:bytes %s-%s/%s\', $ranges[\'start\'], $ranges[\'end\'], $file_size));\r\n                \r\n                // fp指针跳到断点位置\r\n                fseek($fp, sprintf(\'%u\', $ranges[\'start\']));\r\n            }else{\r\n                header(\'HTTP/1.1 200 OK\');\r\n                header(\'content-length:\'.$file_size);\r\n            }\r\n\r\n            while(!feof($fp)){\r\n                echo fread($fp, round($this->_speed*1024,0));\r\n                ob_flush();\r\n                //sleep(1); // 用于测试,减慢下载速度\r\n            }\r\n\r\n            ($fp!=null) && fclose($fp);\r\n\r\n        }else{\r\n            return \'\';\r\n        }\r\n    }\r\n\r\n\r\n    /** 设置下载速度\r\n    * @param int $speed\r\n    */\r\n    public function setSpeed($speed){\r\n        if(is_numeric($speed) && $speed>16 && $speed<4096){\r\n            $this->_speed = $speed;\r\n        }\r\n    }\r\n\r\n\r\n    /** 获取header range信息\r\n    * @param  int   $file_size 文件大小\r\n    * @return Array\r\n    */\r\n    private function getRange($file_size){\r\n        if(isset($_SERVER[\'HTTP_RANGE\']) && !empty($_SERVER[\'HTTP_RANGE\'])){\r\n            $range = $_SERVER[\'HTTP_RANGE\'];\r\n            $range = preg_replace(\'/[\\s|,].*/\', \'\', $range);\r\n            $range = explode(\'-\', substr($range, 6));\r\n            if(count($range)<2){\r\n                $range[1] = $file_size;\r\n            }\r\n            $range = array_combine(array(\'start\',\'end\'), $range);\r\n            if(empty($range[\'start\'])){\r\n                $range[\'start\'] = 0;\r\n            }\r\n            if(empty($range[\'end\'])){\r\n                $range[\'end\'] = $file_size;\r\n            }\r\n            return $range;\r\n        }\r\n        return null;\r\n    }\r\n\r\n} // class end\r\n\r\n?>


    调用方法

    <?php\r\n\r\nrequire(\'FileDownload.class.php\');\r\n$file = \'book.zip\';\r\n$name = time().\'.zip\';\r\n$obj = new FileDownload();\r\n$flag = $obj->download($file, $name);\r\n//$flag = $obj->download($file, $name, true); // 断点续传\r\n\r\nif(!$flag){\r\n    echo \'file not exists\';\r\n}\r\n\r\n?>


    断点续传测试方法:

    使用linux wget命令去测试下载, wget -c -O file http://xxx

    '); +INSERT INTO `ape_document_article` VALUES (23, '

    php 支持断点续传的文件下载方法

    /** php下载类,支持断点续传
    * Date: 2013-06-30
    * Author: fdipzone
    * Ver: 1.0
    *
    * Func:
    * download: 下载文件
    * setSpeed: 设置下载速度
    * getRange: 获取header中Range
    */

    /** 下载
    * @param String $file 要下载的文件路径
    * @param String $name 文件名称,为空则与下载的文件名称一样
    * @param int $speed 下载速度
    * @param boolean $reload 是否开启断点续传
    */
    function download($file, $name=\'\',$speed=512, $reload=false){
    if(file_exists($file)){
    if($name==\'\'){
    $name = basename($file);
    }
    if(is_numeric($speed) && $speed>16 && $speed<4096){
    $_speed = $speed;
    }else{
    $_speed=512;
    }
    $fp = fopen($file, \'rb\');
    $file_size = filesize($file);
    $ranges =getRange($file_size);

    header(\'cache-control:public\');
    header(\'content-type:application/octet-stream\');
    header(\'content-disposition:attachment; filename=\'.$name);

    if($reload && $ranges!=null){ // 使用续传
    header(\'HTTP/1.1 206 Partial Content\');
    header(\'Accept-Ranges:bytes\');

    // 剩余长度
    header(sprintf(\'content-length:%u\',$ranges[\'end\']-$ranges[\'start\']));

    // range信息
    header(sprintf(\'content-range:bytes %s-%s/%s\', $ranges[\'start\'], $ranges[\'end\'], $file_size));

    // fp指针跳到断点位置
    fseek($fp, sprintf(\'%u\', $ranges[\'start\']));
    }else{
    header(\'HTTP/1.1 200 OK\');
    header(\'content-length:\'.$file_size);
    }

    while(!feof($fp)){
    echo fread($fp, round($_speed*1024,0));
    ob_flush();
    //sleep(1); // 用于测试,减慢下载速度
    }

    ($fp!=null) && fclose($fp);

    }else{
    return \'\';
    }
    }


    /** 获取header range信息
    * @param int $file_size 文件大小
    * @return Array
    */
    function getRange($file_size){
    if(isset($_SERVER[\'HTTP_RANGE\']) && !empty($_SERVER[\'HTTP_RANGE\'])){
    $range = $_SERVER[\'HTTP_RANGE\'];
    $range = preg_replace(\'/[\\s|,].*/\', \'\', $range);
    $range = explode(\'-\', substr($range, 6));
    if(count($range)<2){
    $range[1] = $file_size;
    }
    $range = array_combine(array(\'start\',\'end\'), $range);
    if(empty($range[\'start\'])){
    $range[\'start\'] = 0;
    }
    if(empty($range[\'end\'])){
    $range[\'end\'] = $file_size;
    }
    return $range;
    }
    return null;
    }
    download(\'visualparadigmshisi.rar\');


    thinkphp使用或类使用方法

        /** 下载
    * @param String $file 要下载的文件路径
    * @param String $name 文件名称,为空则与下载的文件名称一样
    * @param int $speed 下载速度
    * @param boolean $reload 是否开启断点续传
    */
    public function download($file, $name=\'\',$speed=512, $reload=false){
    if(file_exists($file)){
    if($name==\'\'){
    $name = basename($file);
    }
    if(is_numeric($speed) && $speed>16 && $speed<4096){
    $_speed = $speed;
    }else{
    $_speed=512;
    }
    $fp = fopen($file, \'rb\');
    $file_size = filesize($file);
    $ranges =$this->getRange($file_size);

    header(\'cache-control:public\');
    header(\'content-type:application/octet-stream\');
    header(\'content-disposition:attachment; filename=\'.$name);

    if($reload && $ranges!=null){ // 使用续传
    header(\'HTTP/1.1 206 Partial Content\');
    header(\'Accept-Ranges:bytes\');

    // 剩余长度
    header(sprintf(\'content-length:%u\',$ranges[\'end\']-$ranges[\'start\']));

    // range信息
    header(sprintf(\'content-range:bytes %s-%s/%s\', $ranges[\'start\'], $ranges[\'end\'], $file_size));

    // fp指针跳到断点位置
    fseek($fp, sprintf(\'%u\', $ranges[\'start\']));
    }else{
    header(\'HTTP/1.1 200 OK\');
    header(\'content-length:\'.$file_size);
    }

    while(!feof($fp)){
    echo fread($fp, round($_speed*1024,0));
    ob_flush();
    //sleep(1); // 用于测试,减慢下载速度
    }

    ($fp!=null) && fclose($fp);

    }else{
    return \'\';
    }
    }


    /** 获取header range信息
    * @param int $file_size 文件大小
    * @return Array
    */
    public function getRange($file_size){
    if(isset($_SERVER[\'HTTP_RANGE\']) && !empty($_SERVER[\'HTTP_RANGE\'])){
    $range = $_SERVER[\'HTTP_RANGE\'];
    $range = preg_replace(\'/[\\s|,].*/\', \'\', $range);
    $range = explode(\'-\', substr($range, 6));
    if(count($range)<2){
    $range[1] = $file_size;
    }
    $range = array_combine(array(\'start\',\'end\'), $range);
    if(empty($range[\'start\'])){
    $range[\'start\'] = 0;
    }
    if(empty($range[\'end\'])){
    $range[\'end\'] = $file_size;
    }
    return $range;
    }
    return null;
    }
    $this->download(\'visualparadigmshisi.rar\');
    '); +INSERT INTO `ape_document_article` VALUES (24, '

    新创建一个项目初始化

    项目创建在网页完成

    初始化

    echo \"# mzui\" >> README.md

    git init

    git add README.md

    git commit -m \"first commit\"

    git remote add origin https://github.com/1099438829/mzui.git

    git push -u origin master

    更新文件命令

    git remote add origin https://github.com/1099438829/mzui.git

    git push -u origin master


    1 常用

    $ git remote add origin git@github.com:yeszao/dofiler.git         # 配置远程git版本库\r\n$ git pull origin master                                          # 下载代码及快速合并 \r\n$ git push origin master                                          # 上传代码及快速合并\r\n$ git fetch origin                                                # 从远程库获取代码\r\n\r\n$ git branch                                                      # 显示所有分支\r\n$ git checkout master                                             # 切换到master分支\r\n$ git checkout -b dev                                             # 创建并切换到dev分支\r\n$ git commit -m \"first version\"                                   # 提交\r\n\r\n$ git status                                                      # 查看状态\r\n$ git log                                                         # 查看提交历史\r\n\r\n$ git config core.ignorecase false                                # 设置大小写敏感\r\n$ git config --global user.name \"YOUR NAME\"                       # 设置用户名\r\n$ git config --global user.email \"YOUR EMAIL ADDRESS\"             # 设置邮箱

    2 别名Alias

    $ git config --global alias.br=\"branch\"                 # 创建/查看本地分支\r\n$ git config --global alias.co=\"checkout\"               # 切换分支\r\n$ git config --global alias.cb=\"checkout -b\"            # 创建并切换到新分支\r\n$ git config --global alias.cm=\"commit -m\"              # 提交\r\n$ git config --global alias.st=\"status\"                 # 查看状态\r\n$ git config --global alias.pullm=\"pull origin master\"  # 拉取分支\r\n$ git config --global alias.pushm=\"push origin master\"  # 提交分支\r\n$ git config --global alias.log=\"git log --oneline --graph --decorate --color=always\" # 单行、分颜色显示记录\r\n$ git config --global alias.logg=\"git log --graph --all --format=format:\'%C(bold blue)%h%C(reset) - %C(bold green)(%ar)%C(reset) %C(white)%s%C(reset) %C(bold white)— %an%C(reset)%C(bold yellow)%d%C(reset)\' --abbrev-commit --date=relative\" # 复杂显示

    3 创建版本库

    $ git clone <url>                 # 克隆远程版本库\r\n$ git init                        # 初始化本地版本库

    4 修改和提交

    $ git status                      # 查看状态\r\n$ git diff                        # 查看变更内容\r\n$ git add .                       # 跟踪所有改动过的文件\r\n$ git add <file>                  # 跟踪指定的文件\r\n$ git mv <old> <new>              # 文件改名\r\n$ git rm <file>                   # 删除文件\r\n$ git rm --cached <file>          # 停止跟踪文件但不删除\r\n$ git commit -m “commit message”  # 提交所有更新过的文件\r\n$ git commit --amend              # 修改最后一次提交

    5 查看提交历史

    $ git log                         # 查看提交历史\r\n$ git log -p <file>               # 查看指定文件的提交历史\r\n$ git blame <file>                # 以列表方式查看指定文件的提交历史

    6 撤消

    $ git reset --hard HEAD           # 撤消工作目录中所有未提交文件的修改内容\r\n$ git reset --hard <version>      # 撤销到某个特定版本\r\n$ git checkout HEAD <file>        # 撤消指定的未提交文件的修改内容\r\n$ git checkout -- <file>          # 同上一个命令\r\n$ git revert <commit>             # 撤消指定的提交

    7 分支与标签

    $ git branch                      # 显示所有本地分支\r\n$ git checkout <branch/tag>       # 切换到指定分支或标签\r\n$ git branch <new-branch>         # 创建新分支\r\n$ git branch -d <branch>          # 删除本地分支\r\n$ git tag                         # 列出所有本地标签\r\n$ git tag <tagname>               # 基于最新提交创建标签\r\n$ git tag -a \"v1.0\" -m \"一些说明\"  # -a指定标签名称,-m指定标签说明\r\n$ git tag -d <tagname>            # 删除标签\r\n\r\n$ git checkout dev                # 合并特定的commit到dev分支上\r\n$ git cherry-pick 62ecb3

    8 合并与衍合

    $ git merge <branch>              # 合并指定分支到当前分支\r\n$ git merge --abort               # 取消当前合并,重建合并前状态\r\n$ git merge dev -Xtheirs          # 以合并dev分支到当前分支,有冲突则以dev分支为准\r\n$ git rebase <branch>             # 衍合指定分支到当前分支

    9 远程操作

    $ git remote -v                   # 查看远程版本库信息\r\n$ git remote show <remote>        # 查看指定远程版本库信息\r\n$ git remote add <remote> <url>   # 添加远程版本库\r\n$ git remote remove <remote>      # 删除指定的远程版本库\r\n$ git fetch <remote>              # 从远程库获取代码\r\n$ git pull <remote> <branch>      # 下载代码及快速合并\r\n$ git push <remote> <branch>      # 上传代码及快速合并\r\n$ git push <remote> :<branch/tag-name> # 删除远程分支或标签\r\n$ git push --tags                 # 上传所有标签

    10 打包

    $ git archive --format=zip --output ../file.zip master    # 将master分支打包成file.zip文件,保存在上一级目录\r\n$ git archive --format=zip --output ../v1.2.zip v1.2      # 打包v1.2标签的文件,保存在上一级目录v1.2.zip文件中\r\n$ git archive --format=zip v1.2 > ../v1.2.zip             # 作用同上一条命令\r\n

    git打包命令会自动忽略.gitignore中指定的目录和文件,以及.git目录。

    11 全局和局部配置

    12 远程与本地合并

    如果在远程创建了代码仓,而且已经初始化,本地是具体的源代码,那么工作流程应该是:

    $ git init                              # 初始化本地代码仓\r\n$ git add .                             # 添加本地代码\r\n$ git commit -m \"add local source\"      # 提交本地代码\r\n$ git pull origin master                # 下载远程代码\r\n$ git merge master                      # 合并master分支\r\n$ git push -u origin master             # 上传代码

     

    '); +INSERT INTO `ape_document_article` VALUES (25, '
    <?php\r\n@ini_set(\'date.timezone\', \'Asia/Shanghai\');\r\n@ini_set(\'display_errors\', 1);\r\nheader(\'Content-Type:text/html;charset=utf-8\');\r\nclass Time\r\n{\r\n    public static function times($btime)\r\n    {\r\n        $result = \'\';\r\n        $time =time() - $btime ;\r\n        if($time < 60)\r\n        {\r\n            $result = $time.\'秒前\';\r\n        }\r\n        else if($time < 1800)\r\n        {\r\n            $result = floor($time/60).\'分钟前\';\r\n        }\r\n        else if($time < 3600)\r\n        {\r\n            $result = \'半小时前\';\r\n        }\r\n        else if($time < 86400)\r\n        {\r\n            $result = floor($time/3600).\'小时前\';\r\n        }\r\n        else\r\n        {\r\n            $zt = strtotime(date(\'Y-m-d 00:00:00\'));\r\n            $qt = strtotime(date(\'Y-m-d 00:00:00\',strtotime(\"-1 day\")));\r\n            $st = strtotime(date(\'Y-m-d 00:00:00\',strtotime(\"-2 day\")));\r\n            $bt = strtotime(date(\'Y-m-d 00:00:00\',strtotime(\"-7 day\")));\r\n            if( $btime < $bt)\r\n            {\r\n                $result = date(\'Y-m-d H:i:s\', $btime);\r\n            }\r\n            else if($btime < $st)\r\n            {\r\n                $result = floor($time/86400).\'天前\';\r\n            }\r\n            else if($btime < $qt)\r\n            {\r\n                $result = \"前天\".date(\'H:i\', $btime);\r\n            }\r\n            else\r\n            {\r\n                $result = \'昨天\'.date(\'H:i\', $btime);\r\n            }\r\n        }\r\n        return $result;\r\n    }\r\n}\r\n//测试\r\n$str=\'2013-09-25 00:13:05\';\r\necho Time::times(strtotime($str));
    '); +INSERT INTO `ape_document_article` VALUES (26, '

    安全是编程非常重要的一个方面。在任何一种编程语言中,都提供了许多的函数或者模块来确保程序的安全性。在现代网站应用中,经常要获取来自世界各地用户的输入,但是,我们都知道“永远不能相信那些用户输入的数据”。所以在各种的Web开发语言中,都会提供保证用户输入数据安全的函数。今天,我们就来看看,在著名的开源语言PHP中,有哪些有用的安全函数。

    在PHP中,有些很有用的函数,防止你的网站遭受各种攻击,例如SQL注入攻击XSS攻击(Cross Site Scripting:跨站脚本)等。一起看看PHP中常用的、可以确保项目安全的函数。注意,这并不是完整的列表,是我觉得在实际项目中很有的一些函数。

    mysql_real_escape_string()

    mysql_real_escape_string() 函数在PHP中防止SQL注入攻击时非常有用。这个函数会对一些特殊字符,例如单引号\'、双引号\"、反斜杠\\等添加一个反斜杠,以确保在查询这些数据之前用户提供的输入是干净的。

    注意,仅在写数据库的时候才需要调用这个函数,在读取数据库的时候不需要调用 stripslashes() 来unescape数据,因为这些反斜杠是在数据库执行SQL的时候添加的,当把数据写入到数据库的时候,反斜杠会被移除,所以写入到数据库的内容就是原始数据,并不会在前面多了反斜杠。

    从 PHP5.5.0 开始已经不推荐使用 mysql_real_escape_string() 了,所有新的应用应该使用 MySQLi 和 PDO_MySQL 扩展提供的方法:mysqli_real_escape_string() 或者 PDO::quote() 函数库执行数据库操作,以防止SQL注入攻击。

    addslashes()

    这个函数的原理跟 mysql_real_escape_string() 相似。但是如果 php.ini 文件中的magic_quotes_gpc的值是on,就不要使用这个函数,因为PHP已经对GPC($_GET$_POST和 $_COOKIE)数据自动运行 addslashes()。再使用 addslashes(),会导致双层转义。在PHP程序中,可以使用 get_magic_quotes_gpc() 函数来确定它是否开启。

    注意,在 PHP5.3.0 之前,magic_quotes_gpc 是默认 on 的,所以不需要在这些变量上重复调用 addslashes()。不过 magic_quotes_gpc 在 PHP5.3 就已经被废弃,从 PHP5.4 已经被移除了。如果使用 PHP5.4以后的版本,可以不用担心这个问题,PHP 会自动转移GPC和$_ENV数据。

    stripslashes() 可以去除 addslashes() 函数添加的反斜杠。

    htmlspecialchars()

    htmlspecialchars() 函数对于过滤用户输入的数据非常有用。它会将一些特殊字符如&\"\'<>转换为HTML实体。例如,用户输入< 时,就会被该函数转化为HTML实体 &lt;。(HTML实体对照表:http://www.w3school.com.cn/html/html_entities.asp),可以防止XSS和SQL注入攻击。

    注意,htmlspecialchars() 函数只是把认为有安全隐患的HTML字符进行转换,如果想要把HTML所有可以转义的字符都进行转义,请使用htmlentities()

    htmlspecialchars_decode() 与 htmlspecialchars() 相反,可以将HTML实体转回为原字符。

    htmlentities()

    htmlentities() 功能同 htmlspecialchars(),不同的是,它可以转义所有的 HTML字符。

    html_entity_decode() 为 htmlentities() 的decode函数。

    strip_tags()

    strip_tags() 函数可以去除字符串中所有的HTML、JavaScript和PHP标签,当然你也可以通过设置该函数的第二个参数,让一些特定的标签出现。

    md5()

    从安全的角度来说,在数据库中直接存储密码的行为不值得推荐。md5() 函数可以为给定字符串产生一个32个字符的md5散列,而且这个过程不可逆,也就是说,你不能从md5()的结果得到原始字符串。

    现在这个函数并不被认为是安全的,因为开源的数据库可以反向检查一个散列值的明文,你可以在这里找到一个MD5散列数据库列表。

    sha1()

    sha1() 函数与md5()类似,但是它使用了不同的算法来产生40个字符的 SHA-1 散列(md5 产生的是32个字符的散列)。也不要把绝对安全寄托在这个函数上,否则会有意想不到的结果。

    intval()

    先别笑,我知道这个函数和安全没什么关系。intval()函数是将变量转成整数类型,你可以用这个函数让你的PHP代码更安全,特别是当你在解析id、年龄这样的数据时。

    '); +INSERT INTO `ape_document_article` VALUES (27, '

    在MySQL中,选择正确的数据类型,对于性能至关重要。一般应该遵循下面两步:(1)确定合适的大类型:数字、字符串、时间、二进制;(2)确定具体的类型:有无符号、取值范围、变长定长等。

    在数据类型设置方面,尽量用更小的数据类型,因为它们通常有更好的性能,花费更少的硬件资源。并且,尽量把字段定义为NOT NULL,避免使用NULL

    1 数值类型

    1.1 说明

    类型大小范围(有符号)范围(无符号)用途
    TINYINT1 字节(-128, 127)(0, 255)小整数值
    SMALLINT2 字节(-32 768, 32 767)(0, 65 535)大整数值
    MEDIUMINT3 字节(-8 388 608, 8 388 607)(0, 16 777 215)大整数值
    INT或INTEGER4 字节(-2 147 483 648, 2 147 483 647)(0, 4 294 967 295)大整数值
    BIGINT8 字节(-9 233 372 036 854 775 808, 9 223 372 036 854 775 807)(0, 18 446 744 073 709 551 615)极大整数值
    FLOAT4 字节(-3.402 823 466 E+38, 1.175 494 351 E-38),0,(1.175 494 351 E-38,3.402 823 466 351 E+38)0, (1.175 494 351 E-38, 3.402 823 466 E+38)单精度
    浮点数值
    DOUBLE8 字节(1.797 693 134 862 315 7 E+308, 2.225 073 858 507 201 4 E-308), 0, (2.225 073 858 507 201 4 E-308, 1.797 693 134 862 315 7 E+308)0, (2.225 073 858 507 201 4 E-308, 1.797 693 134 862 315 7 E+308)双精度
    浮点数值
    DECIMAL对DECIMAL(M,D) ,如果M>D,为M+2否则为D+2依赖于M和D的值依赖于M和D的值小数值

    1.2 优化建议

    1. 如果整形数据没有负数,如ID号,建议指定为UNSIGNED无符号类型,容量可以扩大一倍。
    2. 建议使用TINYINT代替ENUMBITENUMSET
    3. 避免使用整数的显示宽度,也就是说,不要用INT(10)类似的方法指定字段显示宽度,直接用INT。关于INT显示宽度
    4. INT UNSIGNED来存储IPv4地址,用VARBINARY来存储IPv6地址,当然存储之前需要用PHP函数转换。
    5. DECIMAL最适合保存准确度要求高,而且用于计算的数据,比如价格。但是在使用DECIMAL类型的时候,注意长度设置。
    6. 建议使用整形类型来运算和存储实数,方法是,实数乘以相应的倍数后再操作。
    7. 整数通常是最佳的数据类型,因为它速度快,并且能使用AUTO_INCREMENT

    2 日期和时间

    2.1 说明

    类型大小
    (字节)
    范围格式用途
    DATE31000-01-01 到 9999-12-31YYYY-MM-DD日期值
    TIME3\'-838:59:59\' 到 \'838:59:59\'HH:MM:SS时间值或持续时间
    YEAR11901 到 2155YYYY年份值
    DATETIME81000-01-01 00:00:00 到 9999-12-31 23:59:59YYYY-MM-DD HH:MM:SS混合日期和时间值
    TIMESTAMP81970-01-01 00:00:00 到 2037 年某时YYYYMMDDhhmmss混合日期和时间值,时间戳

    2.2 优化建议

    1. MySQL能存储的最小时间粒度为秒。
    2. 建议用DATE数据类型来保存日期。MySQL中默认的日期格式是yyyy-mm-dd
    3. 用MySQL的内建类型DATETIMEDATETIME来存储时间,而不是使用字符串。
    4. 当数据格式为TIMESTAMPDATETIME时,可以用CURRENT_TIMESTAMP作为默认(MySQL5.6以后),MySQL会自动返回记录插入的确切时间。
    5. TIMESTAMP是UTC时间戳,与时区相关。
    6. DATETIME的存储格式是一个YYYYMMDD HH:MM:SS的整数,与时区无关,你存了什么,读出来就是什么。
    7. 除非有特殊需求,否则建议使用TIMESTAMP,它比DATETIME更节约空间。
    8. 有时人们把Unix的时间戳保存为整数值,但是这通常没有任何好处,这种格式处理起来不太方便,我们并不推荐它。

    3 字符串

    3.1 说明

    类型大小用途
    CHAR0-255字节定长字符串
    VARCHAR0-65535 字节变长字符串
    TINYBLOB0-255字节不超过 255 个字符的二进制字符串
    TINYTEXT0-255字节短文本字符串
    BLOB0-65 535字节二进制形式的长文本数据
    TEXT0-65 535字节长文本数据
    MEDIUMBLOB0-16 777 215字节二进制形式的中等长度文本数据
    MEDIUMTEXT0-16 777 215字节中等长度文本数据
    LONGBLOB0-4 294 967 295字节二进制形式的极大文本数据
    LONGTEXT0-4 294 967 295字节极大文本数据

    3.2 优化建议

    1. 字符串的长度相差较大用VARCHAR;字符串短,且所有值都接近一个长度用CHAR
    2. CHARVARCHAR适用于包括人名、邮政编码、电话号码和不超过255个字符长度的任意字母数字组合。那些要用来计算的数字不要用VARCHAR类型保存,因为可能会导致一些与计算相关的问题。换句话说,可能影响到计算的准确性和完整性。
    3. BINARYVARBINARY存储的是二进制字符串,与字符集无关。
    4. BLOB系列存储二进制字符串,与字符集无关。TEXT系列存储非二进制字符串,与字符集相关。一般情况下,你可以认为BLOB是一个更大的VARBINARYTEXT是一个更大的VARCHAR
    5. BLOBTEXT都不能有默认值。

    4 INT显示宽度

    我们经常会使用命令来创建数据表,而且同时会指定一个长度,如下。但是,这里的长度并非是TINYINT类型存储的最大长度,而是显示的最大长度。

    CREATE TABLE `user`(\r\n    `id` TINYINT(2) UNSIGNED\r\n);

    这里表示user表的id字段的类型是TINYINT,可以存储的最大数值是255。所以,

    在存储数据时,如果存入值小于等于255,如200,虽然超过2位,但是没有超出TINYINT类型长度,所以可以正常保存;如果存入值大于255,如500,那么MySQL会自动保存为TINYINT类型的最大值255

    在查询数据时,不管查询结果为何值,都按实际输出。这里TINYINT(2)2的作用就是,当需要在查询结果前填充0时,命令中加上ZEROFILL就可以实现,如:

    `id` TINYINT(2) UNSIGNED ZEROFILL

    这样,查询结果如果是5,那输出就是05。如果指定TINYINT(5),那输出就是00005,其实实际存储的值还是5,而且存储的数据不会超过255,只是MySQL输出数据时在前面填充了0

    换句话说,在MySQL命令中,字段的类型长度TINYINT(2)INT(11)不会影响数据的插入,只会在使用ZEROFILL时有用,让查询结果前填充0

    '); +INSERT INTO `ape_document_article` VALUES (28, '

    为方便查询,特整理MySQL常用命令,如下。所有命令都亲手检验过,请放心使用:)

    约定:$后为Shell环境命令,>后为MySQL命令。

    1 常用命令

    第一步,连接数据库。

    $ mysql -u root -p                           # 进入MySQL bin目录后执行,回车后输入密码连接。\r\n                                             # 常用参数:-h 服务器地址,-u 用户名,-p 密码,-P 端口

    然后是一些常用的命令。
    数据库操作:

    > create database dbname;                    # 创建数据库,数据库名为dbname\r\n> CREATE DATABASE `todo` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;  # 创建todo数据库,并指定字符集\r\n> show databases;                            # 显示所有数据库\r\n> alter database character set utf8;         # 修改数据库字符集\r\n> use dbname;                                # 选择数据库\r\n> status;                                    # 查看当前选择(use)的数据库\r\n> drop database dbname;                      # 删除数据库\r\n

    数据表操作:

    > show tables;                               # 显示所有表\r\n> describe tablename;                        # 表结构详细描述\r\n> desc tablename;                            # 同 describe 命令一样\r\n> create table newtable like oldtable;       # 复制表结构\r\n> insert into newtable select * from oldtable;  #复制表数据\r\n> rename table tablelname to new_tablelname  # 重命名表,同时命名多个表用逗号“,”分割\r\n> drop table tablename;                      # 删除表\r\n

    界面操作:

    > select version(),current_date;             # 显示当前mysql版本和当前日期\r\n> exit                                       # 返回Shell命令行

    2 创建数据表

    create table命令用来创建数据表,格式:

    create table <表名> (<字段名1> <类型1> [,..<字段名n> <类型n>]);

    数据的类型之后还可以包含:数据宽度 + 是否为空 + 是否主键 + 自动增加 + 默认值,它们书写时不限顺序。但是字段名和字段类型必须是第一和第二位。例如,建立一个名为user的表:

    mysql> create table user(\r\n    -> id int(4) not null primary key auto_increment,\r\n    -> name char(20) not null,\r\n    -> sex int(4) not null default \'0\',\r\n    -> degree double(16,2)\r\n    -> );

    3 修改root的密码

    $ mysqladmin -u root password                     # 原始密码为空的情况\r\nNew password: <输入新的密码>\r\nConfirm new password: <再次输入新密码>\r\n\r\n$ mysqladmin -u root -p password                  # 原始密码不为空的情况\r\nEnter password: <输入旧的密码>\r\nNew password: <输入新的密码>\r\nConfirm new password: <再次输入新密码>\r\n\r\n$ mysqladmin -uroot -p123456 password             # 原始密码不为空的情况,效果和第二种方法一样,只是显式的输入了原始密码\r\nNew password: <输入新的密码>\r\nConfirm new password: <再次输入新密码>

    4 备份和恢复

    $ mysqldump -u root -p dbname > dbname.sql                        # 备份整个数据库(包含表结构和数据)\r\n$ mysqldump -u root -p -d dbname > dbname.sql                     # 备份数据库表结构,不包含数据,\r\n$ mysqldump -u root -p dbname tablename > tablename.sql           # 备份数据库中的某张数据表(包含表结构和数据)\r\n$ mysqldump -u root -p dbname tablename1 tablename2 > tables.sql  # 备份数据库中2张数据表\r\n$ mysqldump -u root -p -d dbname tablename > tablename.sql        # 备份数据库中的某张数据表的表结构(不含数据)\r\n\r\n$ mysqladmin -u root -p create dbname       # 恢复数据库步骤1:创建数据库\r\n$ mysql -u root -p dbname < dbname.sql      # 恢复数据库步骤2:恢复数据

    如果是网络上的服务器,可以在mysqldump之后用-h指定服务器地址,例如:

    $ mysqldump -h sql.domain.com -u root -p dbname > dbname.sql

    导出查询结果到本地计算机:

    mysql -h127.0.0.1 -P3306 -uroot -proot -Ae \"use test;select * from user where status=4 order by id desc;\" > \"C:\\Users\\Gary\\user.txt\"

    5 用户和权限管理

    MySQL 默认有个root用户,但是这个用户权限太大,一般只在管理数据库时候才用。如果在项目中要连接 MySQL 数据库,则建议新建一个权限较小的用户来连接。在 MySQL 命令行模式下输入如下命令可以为 MySQL 创建一个新用户:

    > CREATE USER username IDENTIFIED BY \'123456\';        # 其中,username是用户名,123456是用户密码\r\n

    新用户创建完成,但是此刻如果以此用户登陆的话,会报错,因为我们还没有为这个用户分配相应权限,分配权限的命令是grant,格式为:

    GRANT <权限> ON <数据库>.<表名> TO <用户名>@<登录主机> IDENTIFIED BY \"<密码>\"

    其中,权限可以是:allselectinsertdeleteupdatedrop等值。

    于是,用下面的命令就可以执行特定的功能:

    > GRANT ALL ON *.* TO \'username\'@\'localhost\' IDENTIFIED BY \'123456\';                  # 给用户 username 分配所有数据库的所有权限\r\n> REVOKE ALL ON *.* FROM \'username\'@\'localhost\';                                      # 如果觉得上面的权限太大,用 REVOKE 删除原来权限\r\n> GRANT ALL ON dbname.* TO \'username\'@\'localhost\' IDENTIFIED BY \'123456\';             # 重新授予仅在dbname数据库上的权限\r\n> GRANT SELECT, UPDATE ON dbname.* TO \'username\'@\'localhost\' IDENTIFIED BY \'123456\';  # 仅授予selectupdate权限,无法执行insertdelete等命令\r\n> FLUSH PRIVILEGES;                                                                   # 每当调整权限后,通常需要用这个命令刷新权限\r\n> DROP USER username@localhost;                                                       # 删除用户\r\n

    仔细观察上面几个命令,可以发现不管是授权,还是删除授权,都要指定响应的host(即@符号后面的登录主机,主机也可以用%通配符表示所有主机,或者192.168.1.% 表示特定主机段)。因为以上及格命令实际上都是在操作 mysql 数据库中的user表,可以用如下命令查看相应用户及对应的host:

    SELECT user, host FROM user;\r\n

    当然,这个表中还包含很多其它例如用户密码、权限设置等很多内容,操作时候尤其需要小心。

    '); +INSERT INTO `ape_document_article` VALUES (29, '

    1. php文件夹操作函数

    1. string basename ( string path [, string suffix] )

    给出一个包含有指向一个文件的全路径的字符串,本函数返回基本的文件名。如果文件名是以 suffix 结束的,那这一部分也会被去掉。

    在 Windows 中,斜线(/)和反斜线()都可以用作目录分隔符。在其它环境下是斜线(/)。

    例子:

    1. <?php
    2. $path = \"/testweb/home.php\";
    3. //显示带有文件扩展名的文件名
    4. echo basename($path);
    5. //显示不带有文件扩展名的文件名
    6. echo basename($path,\".php\");
    7. ?>

    输出:

    1. home.php
    2. home
    1. string dirname ( string path )

    给出一个包含有指向一个文件的全路径的字符串,本函数返回去掉文件名后的目录名。

    在 Windows 中,斜线(/)和反斜线()都可以用作目录分隔符。在其它环境下是斜线(/)。

     

    1. array pathinfo ( string path [, int options] )

    pathinfo() 返回一个联合数组包含有 path 的信息。包括以下的数组单元:dirname,basename 和 extension。

    可以通过参数 options 指定要返回哪些单元。它们包括:PATHINFO_DIRNAME,PATHINFO_BASENAME 和 PATHINFO_EXTENSION。默认是返回全部的单元。

     

    1. array scandir ( string $directory [, int $sorting_order [, resource $context ]] )

    scandir, 列出指定路径中的文件和目录,返回一个 array,包含有 directory 中的文件和目录。成功则返回包含有文件名的 array,如果失败则返回 FALSE。如果 directory 不是个目录,则返回布尔值 FALSE 并生成一条 E_WARNING 级的错误。 

    例子:

    1. <?php
    2. $dir = \'/tmp\';
    3. $files1 = scandir($dir);
    4. $files2 = scandir($dir, 1);
    5. print_r($files1);
    6. print_r($files2);
    7. ?>

    输出:

    1. Array
    2. (
    3. [0] => .
    4. [1] => ..
    5. [2] => bar.php
    6. [3] => foo.txt
    7. [4] => somedir
    8. )
    9. Array
    10. (
    11. [0] => somedir
    12. [1] => foo.txt
    13. [2] => bar.php
    14. [3] => ..
    15. [4] => .
    16. )
    1. string realpath ( string path )

    realpath() 扩展所有的符号连接并且处理输入的 path 中的 ‘/./’, ‘/../’ 以及多余的 ‘/’ 并返回规范化后的绝对路径名。返回的路径中没有符号连接,’/./’ 或 ‘/../’ 成分。

    realpath() 失败时返回 FALSE,比如说文件不存在的话。在 BSD 系统上,如果仅仅是 path 不存在的话,PHP 并不会像其它系统那样返回 FALSE。

     

    1. bool is_dir ( string filename )

    如果文件名存在并且为目录则返回 TRUE。如果 filename 是一个相对路径,则按照当前工作目录检查其相对路径。

    注: 本函数的结果会被缓存。更多信息参见 clearstatcache()。

     

    1. resource opendir ( string path [, resource context] )

    打开一个目录句柄,可用于之后的 closedir(),readdir() 和 rewinddir() 调用中。

    1. string readdir ( resource dir_handle )

    返回目录中下一个文件的文件名。文件名以在文件系统中的排序返回。

    1. void closedir ( resource dir_handle )

    关闭由 dir_handle 指定的目录流。流必须之前被 opendir() 所打开。

    1. void rewinddir ( resource dir_handle )

    将 dir_handle 指定的目录流重置到目录的开头。

     

    1. array glob ( string pattern [, int flags] )

    glob() 函数依照 libc glob() 函数使用的规则寻找所有与 pattern 匹配的文件路径,类似于一般 shells 所用的规则一样。不进行缩写扩展或参数替代。

    返回一个包含有匹配文件/目录的数组。如果出错返回 FALSE。

     

    有效标记为: 

    GLOB_MARK - 在每个返回的项目中加一个斜线
    GLOB_NOSORT - 按照文件在目录中出现的原始顺序返回(不排序)
    GLOB_NOCHECK - 如果没有文件匹配则返回用于搜索的模式
    GLOB_NOESCAPE - 反斜线不转义元字符
    GLOB_BRACE - 扩充 {a,b,c} 来匹配 ‘a’,’b’ 或 ‘c’
    GLOB_ONLYDIR - 仅返回与模式匹配的目录项

    注: 在 PHP 4.3.3 版本之前 GLOB_ONLYDIR 在 Windows 或者其它不使用 GNU C 库的系统上不可用。

    GLOB_ERR - 停止并读取错误信息(比如说不可读的目录),默认的情况下忽略所有错误

    注: GLOB_ERR 是 PHP 5.1 添加的。

     

    2. php文件目录操作

    a. 新建文件

    1、先确定要写入文件的内容

    1. $content = \'你好\';

    2、打开这个文件(系统会自动建立这个空文件)

    1. //假设新建的文件叫file.txt,而且在上级目录下。w表示‘写文件’,$fp下面要用到,表示指向某个打开的文件。
    2. $fp = fopen(\'../file.txt\', \'w\');

    3、将内容字符串写入文件

    1. //$fp告诉系统要写入的文件,写入的内容是$content
    2. fwrite($fp, $content);

    4、关闭文件

    1. fclose($fp); 

    注意:PHP5中提供了更方便的函数file_put_contents,上面的4步可以这样完成:

    1. $content = \'你好\';
    2. file_put_contents(\'file.txt\',$content);

     

    b. 删除文件

    删除当前目录下的arch目录下的文件abc.txt

    1. unlink(\'arch/abc.txt\');

    注意:系统会返回操作结果,成功则返回 TRUE,失败则返回 FALSE,可以用变量接收,就知道是否删除成功:

    1. $deleteResult = unlink(\'arch/abc.txt\');

     

    c. 获取文件内容

    假设获取的目标文件名是file.txt,而且在上级目录下。获取的内容放入$content。

    1. $content = file_get_contents(\'../file.txt\');

     

    d. 修改文件内容

    操作方法与新建内容基本一样

     

    e. 重命名文件或目录

    将当前目录下的子目录a下面的文件1.gif重命名为2.gif。

    1. rename(\'/a/1.gif\', \'/a/2.gif\');

    注意:对目录也一样。系统会返回操作结果,成功则返回 TRUE,失败则返回 FALSE,可以用变量接收,就知道是否重命名成功。

    1. $renameResult = rename(\'/a/1.gif\', \'/a/2.gif\');

    如果要移动文件或目录,只要将重命名后的路径设置为新的路径就可以了:

    将当前目录下的子目录a下面的文件1.gif,移动到当前目录下的子目录b,并且重命名为2.gif。

    1. rename(\'/a/1.gif\', \'/b/2.gif\');

    不过要注意,如果目录b不存在,就会移动失败。

     

    f. 复制文件

    将当前目录下的子目录a下面的文件1.gif,复制到当前目录下的子目录b,并命名为2.gif。

    1. copy(\'/a/1.gif\', \'/b/1.gif\');

    注意:不能对目录进行此项操作。

    如果目标文件(上面的/b/1.gif)已经存在,原来的文件将被覆盖。

    系统会返回操作结果,成功则返回 TRUE,失败则返回 FALSE,可以用变量接收,就知道是否复制成功。

    1. $copyResult = copy(\'/a/1.gif\', \'/b/1.gif\');

     

    g. 移动文件或目录

    操作方法和重命名一样

     

    h. 文件或目录是否存在

    检查上级目录下的文件logo.jpg是否存在。

    1. $existResult = file_exists(\'../logo.jpg\');

    注意:如果文件存在系统返回true,否则返回false。可以对目录进行同样的操作。

     

    i. 获取文件大小

    获取上级目录下的文件logo.png的大小。

    1. $size = filesize(\'../logo.png\');

    注意:系统会返回一个数字,表示文件的大小是多少字节(bytes)。

     

    j. 新建目录

    在当前目录下的目录a下面新建目录b。

    1. mkdir(\'/a/b\');

    注意:系统会返回操作结果,成功则返回 TRUE,失败则返回 FALSE,可以用变量接收,就知道是否新建成功:

    1. $mkResult = mkdir(\'/a/b\');

     

    k. 删除目录

    删除当前目录下的目录a下面的子目录b。

    1. rmdir(\'/a/b\');

    注意:只能删除非空的目录,否则必须先删除目录下的子目录和文件,再删除总目录

    系统会返回操作结果,成功则返回 TRUE,失败则返回 FALSE,可以用变量接收,就知道是否删除成功:

    1. $deleteResult = rmdir(\'/a/b\');

     

    l. 获取目录中的所有文件名

    1、先打开要操作的目录,并用一个变量指向它

    打开当前目录下的目录pic下的子目录common。

    1. $handler = opendir(\'pic/common\');

    2、循环的读取目录下的所有文件

    1. while( ($filename = readdir($handler)) !== false )  {
    2.       //3、目录下都会有两个文件,名字为\'.\'和‘..’,不要对他们进行操作
    3.       if($filename != \".\" && $filename != \"..\") {
    4.       //4、进行处理
    5.       //这里简单的用echo来输出文件名
    6.       echo $filename;
    7.       }
    8. }

    注意:其中$filename = readdir($handler)是每次循环的时候将读取的文件名赋值给$filename,为了不陷于死循环,所以还要让$filename !== false。一定要用!==,因为如果某个文件名如果叫\'0\',或者某些被系统认为是代表false,用!=就会停止循环

    5、关闭目录

    1. closedir($handler);

    完整代码:

    1. /**
    2. * 返回一个文件夹下的所有文件,包括子文件夹内的文件。
    3. * @param string $dir 路径
    4. * @return array
    5. */
    6. function scan_dir($dir)
    7. {
    8. $files = array();
    9. if (is_dir($dir)) {
    10. if ($handle = opendir($dir)) {
    11. while (($file = readdir($handle)) !== false) {
    12. if ($file != \".\" && $file != \"..\") {
    13. if (is_dir($dir . \"/\" . $file)) {
    14. $files[$file] = scan_dir($dir . \"/\" . $file);
    15. } else {
    16. $files[] = $dir . \"/\" . $file;
    17. }
    18. }
    19. }
    20. closedir($handle);
    21. return $files;
    22. }
    23. }
    24. }

     

    m. 对象是否是目录

    检查上级目录下的目标对象logo.jpg是否是目录。

    1. $checkResult = is_dir(\'../logo.jpg\');

    注意:如果目标对象是目录系统返回true,否则返回false。上面例子的$checkResult当然是false。

     

    n. 对象是否是文件

    检查上级目录下的目标对象logo.jpg是否是文件。

    1. $checkResult = is_file(\'../logo.jpg\');

    注意:如果目标对象是文件,系统返回true,否则返回false。上面例子的$checkResult当然是true。

    '); +INSERT INTO `ape_document_article` VALUES (30, '
    框架:thinkphp \r\n版本:3.2.3 \r\n内容:查询语句 \r\n解决问题:重复字段问题


    $Data  =  M(\'a\')->where($where)\r\n                            ->Field(\'a.name as aname,b.name as uname,a.*\')\r\n                            ->join(\'b on b.jb_id=a.id\',\'LEFT\')\r\n                            ->order(\'a.id desc\')\r\n                            ->select();


    解释:a.* 查询a表所有的字段 

    a.name as aname 转换a表中的name重复字段为aname

    '); +INSERT INTO `ape_document_article` VALUES (31, '
    <?php\r\nheader(\'Content-type:text/html,charset=utf-8\');\r\nfunction getList($path){\r\n	$list = array();\r\n	$new_dir=\'\';\r\n	$dh=scandir($path);\r\n	$num =count($dh);\r\n	for ($i=0; $i < $num; $i++) { \r\n		// var_dump($dh[$i]);\r\n		if ($dh[$i] ==\'.\' || $dh[$i] == \'..\') {\r\n			continue;\r\n		}\r\n		if ($path !=\'/\') {\r\n			$new_dir = $path.\'/\'.$dh[$i];\r\n		}else{\r\n			$new_dir = $path.$dh[$i];\r\n		}\r\n		\r\n		// var_dump($new_dir);\r\n		if (is_dir($new_dir)) {\r\n			//如果是文件夹\r\n			$list[\'dir\'][]=$new_dir;\r\n			$file_dir=getList($new_dir);//递归开始\r\n    		if ($file_dir[\'dir\']) {\r\n    			//合并文件夹\r\n    			$list[\'dir\']=array_merge($list[\'dir\'],$file_dir[\'dir\']);\r\n    		}\r\n    		if ($file_dir[\'file\']) {\r\n    			//合并文件\r\n    			$list[\'file\']=array_merge($list[\'file\'],$file_dir[\'file\']);\r\n    		}\r\n		}\r\n		if (is_file($new_dir)) {\r\n			$list[\'file\'][]=$new_dir;\r\n		}\r\n	}\r\n	return $list;\r\n}\r\n\r\nfunction getList2($path){\r\n\r\n	$list = array();\r\n	$new_dir=\'\';\r\n	// 打开目录,然后读取其内容\r\n	if (is_dir($path)){\r\n	  if ($dh = opendir($path)){\r\n	    while (($file = readdir($dh)) !== false){\r\n	    	if ($file==\'.\' || $file==\'..\') {\r\n	    		//.和..跳过\r\n	    		continue;\r\n	    	}\r\n	    	//判断是不是根目录\r\n	    	if ($path !=\'/\') {\r\n				$new_dir=$path.\'/\'.$file;\r\n			}else{\r\n				$new_dir=$path.$file;\r\n			}\r\n	    	if (is_dir($new_dir)) {\r\n	    		$list[\'dir\'][]=$new_dir;\r\n	    		$file_dir=getList2($new_dir);//递归开始\r\n	    		if ($file_dir[\'dir\']) {\r\n	    			$list[\'dir\']=array_merge($list[\'dir\'],$file_dir[\'dir\']);\r\n	    		}\r\n	    		if ($file_dir[\'file\']) {\r\n	    			$list[\'file\']=array_merge($list[\'file\'],$file_dir[\'file\']);\r\n	    		}\r\n	    	}elseif (is_file($new_dir)) {\r\n	    		$list[\'file\'][]=$new_dir;\r\n	    	}\r\n	    }\r\n	    closedir($dh);\r\n	    return $list;\r\n	  }\r\n	}\r\n}\r\n\r\nvar_dump(getList(\'E:\\lnmp\'));\r\n
    '); +INSERT INTO `ape_document_article` VALUES (32, '

    借助插件 实现demo见插件

    效果

    \"Image\"

    '); +INSERT INTO `ape_document_article` VALUES (33, '
    mysql复习\r\n一:复习前的准备\r\n1:确认你已安装wamp\r\n2:确认你已安装ecshop,并且ecshop的数据库名为shop\r\n\r\n二	基础知识:\r\n1.数据库的连接\r\nmysql -u -p -h\r\n-u 用户名\r\n-p 密码\r\n-h host主机\r\n\r\n2:库级知识\r\n2.1 显示数据库: show databases;\r\n2.2 选择数据库: use dbname;\r\n2.3 创建数据库: create database dbname charset utf8;\r\n2.3 删除数据库: drop database dbname;\r\n\r\n3: 表级操作:\r\n3.1 显示库下面的表\r\nshow tables;\r\n\r\n3.2 查看表的结构: \r\ndesc tableName;\r\n\r\n3.3 查看表的创建过程: \r\nshow create table  tableName;\r\n\r\n3.4 创建表:\r\n create table tbName (\r\n列名称1 列类型 [列参数] [not null default ],\r\n....列2...\r\n....\r\n列名称N 列类型 [列参数] [not null default ]\r\n)engine myisam/innodb charset utf8/gbk\r\n\r\n\r\n3.4的例子:\r\ncreate table user (\r\n    id int auto_increment,\r\n    name varchar(20) not null default \'\',\r\n    age tinyint unsigned not null default 0,\r\n   index id (id)\r\n   )engine=innodb charset=utf8;\r\n注:innodb是表引擎,也可以是myisam或其他,但最常用的是myisam和innodb,\r\ncharset 常用的有utf8,gbk;\r\n\r\n\r\n3.5 修改表\r\n3.5.1	修改表之增加列:\r\nalter table tbName \r\nadd 列名称1 列类型 [列参数] [not null default ] #(add之后的旧列名之后的语法和创建表时的列声明一样)\r\n\r\n3.5.2	修改表之修改列\r\nalter table tbName\r\nchange 旧列名  新列名  列类型 [列参数] [not null default ]\r\n(注:旧列名之后的语法和创建表时的列声明一样)\r\n\r\n3.5.3	修改表之减少列:\r\nalter table tbName \r\ndrop 列名称;\r\n\r\n\r\n3.5.4	修改表之增加主键\r\nalter table tbName add primary key(主键所在列名);\r\n例:alter table goods add primary key(id)\r\n该例是把主键建立在id列上\r\n\r\n3.5.5	修改表之删除主键\r\nalter table tbName drop primary key;\r\n\r\n3.5.6	修改表之增加索引\r\nalter table tbName add [unique|fulltext] index 索引名(列名);\r\n\r\n3.5.7	修改表之删除索引\r\nalter table tbName drop index 索引名;\r\n\r\n3.5.8	清空表的数据\r\ntruncate tableName;\r\n\r\n4:列类型讲解\r\n列类型:\r\n        整型:tinyint (0~255/-128~127) smallint (0~65535/-32768~32767) mediumint int bigint (参考手册11.2)\r\n        参数解释:\r\n        unsigned 无符号(不能为负)  zerofill 0填充  M 填充后的宽度\r\n        举例:tinyint unsigned;\r\n             tinyint(6) zerofill;   \r\n数值型\r\n        浮点型:float double\r\n        格式:float(M,D)  unsigned\\zerofill;\r\n\r\n\r\n字符型\r\n        char(m) 定长\r\n        varchar(m)变长\r\n        text\r\n\r\n列          实存字符i        实占空间            利用率\r\n\r\nchar(M)      0<=i<=M            M                i/m<=100%\r\n\r\nvarchar(M)    0<=i<=M          i+1,2             i/i+1/2<100%\r\n    \r\n\r\n               year       YYYY	范围:1901~2155. 可输入值2位和4位(如98,2012)\r\n日期时间类型   date       YYYY-MM-DD 如:2010-03-14\r\n               time       HH:MM:SS	如:19:26:32\r\n               datetime   YYYY-MM-DD  HH:MM:SS 如:2010-03-14 19:26:32\r\n               timestamp  YYYY-MM-DD  HH:MM:SS 特性:不用赋值,该列会为自己赋当前的具体时间 \r\n\r\n\r\n\r\n5:增删改查基本操作\r\n\r\n5.1 插入数据 \r\n	insert into 表名(col1,col2,……) values(val1,val2……); -- 插入指定列\r\n	insert into 表名 values (,,,,); -- 插入所有列\r\n	insert into 表名 values	-- 一次插入多行 \r\n	(val1,val2……),\r\n	(val1,val2……),\r\n	(val1,val2……);\r\n\r\n\r\n5.3修改数据\r\n	update tablename \r\n	set \r\n	col1=newval1,  \r\n	col2=newval2,\r\n	...\r\n	...\r\n	colN=newvalN\r\n	where 条件;\r\n\r\n5.4,删除数据    delete from tablenaeme where 条件;\r\n\r\n5.5,    select     查询\r\n\r\n  (1)  条件查询   where  a. 条件表达式的意义,表达式为真,则该行取出\r\n			   b.  比较运算符  = ,!=,< > <=  >=\r\n                           c.  like , not like (\'%\'匹配任意多个字符,\'_\'匹配任意单个字符) \r\n				in , not in , between and\r\n                           d. is null , is not null			\r\n  (2)  分组       group by \r\n			一般要配合5个聚合函数使用:max,min,sum,avg,count\r\n  (3)  筛选       having\r\n  (4)  排序       order by\r\n  (5)  限制       limit\r\n    注意:特殊查询 NULL  ==> is null\r\n\r\n\r\n\r\n6:	连接查询\r\n\r\n6.1, 左连接\r\n	.. left join .. on\r\n	table A left join table B on tableA.col1 = tableB.col2 ; \r\n  例句:\r\n  select 列名 from table A left join table B on tableA.col1 = tableB.col2\r\n2.  右链接: right join\r\n3.  内连接:  inner join\r\n\r\n左右连接都是以在左边的表的数据为准,沿着左表查右表.\r\n内连接是以两张表都有的共同部分数据为准,也就是左右连接的数据之交集.\r\n\r\n7	子查询\r\n  where 型子查询:内层sql的返回值在where后作为条件表达式的一部分\r\n  例句: select * from tableA where colA = (select colB from tableB where ...);\r\n  \r\n  from 型子查询:内层sql查询结果,作为一张表,供外层的sql语句再次查询\r\n  例句:select * from (select * from ...) as tableName where ....\r\n\r\n  \r\n8: 字符集\r\n  客服端sql编码 character_set_client\r\n  服务器转化后的sql编码 character_set_connection\r\n  服务器返回给客户端的结果集编码     character_set_results\r\n  快速把以上3个变量设为相同值: set names 字符集\r\n\r\n   存储引擎 engine=1\\2\r\n  1 Myisam  速度快 不支持事务 回滚\r\n  2 Innodb  速度慢 支持事务,回滚\r\n  \r\n  ①开启事务          start transaction\r\n  ②运行sql;          \r\n  ③提交,同时生效\\回滚 commit\\rollback\r\n\r\n  触发器 trigger\r\n  监视地点:表\r\n  监视行为:增 删 改\r\n  触发时间:after\\before\r\n  触发事件:增 删 改\r\n\r\n\r\n  创建触发器语法\r\n	create trigger tgName\r\n	after/before insert/delete/update \r\n	on tableName\r\n	for each row\r\n	sql; -- 触发语句\r\n	\r\n  删除触发器:drop trigger tgName;\r\n\r\n\r\n 索引\r\n 提高查询速度,但是降低了增删改的速度,所以使用索引时,要综合考虑.\r\n 索引不是越多越好,一般我们在常出现于条件表达式中的列加索引.\r\n 值越分散的列,索引的效果越好\r\n\r\n 索引类型\r\n primary key主键索引\r\n index 普通索引\r\n unique index 唯一性索引\r\n fulltext index 全文索引\r\n\r\n\r\n综合练习:\r\n连接上数据库服务器\r\n创建一个gbk编码的数据库\r\n建立商品表和栏目表,字段如下:\r\n\r\n商品表:goods\r\ngoods_id --主键,\r\ngoods_name -- 商品名称\r\ncat_id  -- 栏目id\r\nbrand_id -- 品牌id\r\ngoods_sn -- 货号\r\ngoods_number -- 库存量\r\nshop_price  -- 价格\r\ngoods_desc --商品详细描述\r\n\r\n栏目表:category\r\ncat_id --主键 \r\ncat_name -- 栏目名称\r\nparent_id -- 栏目的父id\r\n\r\n\r\n\r\n建表完成后,作以下操作:\r\n删除goods表的goods_desc 字段,及货号字段\r\n并增加字段:click_count  -- 点击量\r\n\r\n在goods_name列上加唯一性索引\r\n在shop_price列上加普通索引\r\n在clcik_count列上加普通索引\r\n删除click_count列上的索引\r\n\r\n\r\n对goods表插入以下数据:\r\n+----------+------------------------------+--------+----------+-----------+--------------+------------+-------------+\r\n| goods_id | goods_name                   | cat_id | brand_id | goods_sn  | goods_number | shop_price | click_count |\r\n+----------+------------------------------+--------+----------+-----------+--------------+------------+-------------+\r\n|        1 | KD876                        |      4 |        8 | ECS000000 |           10 |    1388.00 |           7 |\r\n|        4 | 诺基亚N85原装充电器          |      8 |        1 | ECS000004 |           17 |      58.00 |           0 |\r\n|        3 | 诺基亚原装5800耳机           |      8 |        1 | ECS000002 |           24 |      68.00 |           3 |\r\n|        5 | 索爱原装M2卡读卡器           |     11 |        7 | ECS000005 |            8 |      20.00 |           3 |\r\n|        6 | 胜创KINGMAX内存卡            |     11 |        0 | ECS000006 |           15 |      42.00 |           0 |\r\n|        7 | 诺基亚N85原装立体声耳机HS-82 |      8 |        1 | ECS000007 |           20 |     100.00 |           0 |\r\n|        8 | 飞利浦9@9v                   |      3 |        4 | ECS000008 |           17 |     399.00 |           9 |\r\n|        9 | 诺基亚E66                    |      3 |        1 | ECS000009 |           13 |    2298.00 |          20 |\r\n|       10 | 索爱C702c                    |      3 |        7 | ECS000010 |            7 |    1328.00 |          11 |\r\n|       11 | 索爱C702c                    |      3 |        7 | ECS000011 |            1 |    1300.00 |           0 |\r\n|       12 | 摩托罗拉A810                 |      3 |        2 | ECS000012 |            8 |     983.00 |          14 |\r\n|       13 | 诺基亚5320 XpressMusic       |      3 |        1 | ECS000013 |            8 |    1311.00 |          13 |\r\n|       14 | 诺基亚5800XM                 |      4 |        1 | ECS000014 |            4 |    2625.00 |           6 |\r\n|       15 | 摩托罗拉A810                 |      3 |        2 | ECS000015 |            3 |     788.00 |           8 |\r\n|       16 | 恒基伟业G101                 |      2 |       11 | ECS000016 |            0 |     823.33 |           3 |\r\n|       17 | 夏新N7                       |      3 |        5 | ECS000017 |            1 |    2300.00 |           2 |\r\n|       18 | 夏新T5                       |      4 |        5 | ECS000018 |            1 |    2878.00 |           0 |\r\n|       19 | 三星SGH-F258                 |      3 |        6 | ECS000019 |            0 |     858.00 |           7 |\r\n|       20 | 三星BC01                     |      3 |        6 | ECS000020 |           13 |     280.00 |          14 |\r\n|       21 | 金立 A30                     |      3 |       10 | ECS000021 |           40 |    2000.00 |           4 |\r\n|       22 | 多普达Touch HD               |      3 |        3 | ECS000022 |            0 |    5999.00 |          15 |\r\n|       23 | 诺基亚N96                    |      5 |        1 | ECS000023 |            8 |    3700.00 |          17 |\r\n|       24 | P806                         |      3 |        9 | ECS000024 |          148 |    2000.00 |          36 |\r\n|       25 | 小灵通/固话50元充值卡        |     13 |        0 | ECS000025 |            2 |      48.00 |           0 |\r\n|       26 | 小灵通/固话20元充值卡        |     13 |        0 | ECS000026 |            2 |      19.00 |           0 |\r\n|       27 | 联通100元充值卡              |     15 |        0 | ECS000027 |            2 |      95.00 |           0 |\r\n|       28 | 联通50元充值卡               |     15 |        0 | ECS000028 |            0 |      45.00 |           0 |\r\n|       29 | 移动100元充值卡              |     14 |        0 | ECS000029 |            0 |      90.00 |           0 |\r\n|       30 | 移动20元充值卡               |     14 |        0 | ECS000030 |            9 |      18.00 |           1 |\r\n|       31 | 摩托罗拉E8                   |      3 |        2 | ECS000031 |            1 |    1337.00 |           5 |\r\n|       32 | 诺基亚N85                    |      3 |        1 | ECS000032 |            1 |    3010.00 |           9 |\r\n+----------+------------------------------+--------+----------+-----------+--------------+------------+-------------+\r\n\r\n\r\n\r\n三	查询知识\r\n注:以下查询基于ecshop网站的商品表(ecs_goods)\r\n在练习时可以只取部分列,方便查看.\r\n\r\n1: 基础查询 where的练习:\r\n\r\n查出满足以下条件的商品\r\n1.1:主键为32的商品\r\nselect goods_id,goods_name,shop_price \r\n     from ecs_goods\r\n     where goods_id=32;\r\n1.2:不属第3栏目的所有商品\r\nselect goods_id,cat_id,goods_name,shop_price  from ecs_goods\r\n     where cat_id!=3;\r\n\r\n1.3:本店价格高于3000元的商品\r\n\r\n select goods_id,cat_id,goods_name,shop_price  from ecs_goods\r\n     where shop_price >3000;\r\n\r\n1.4:本店价格低于或等于100元的商品\r\nselect goods_id,cat_id,goods_name,shop_price  from ecs_goods where shop_price <=100;\r\n\r\n1.5:取出第4栏目或第11栏目的商品(不许用or)\r\nselect goods_id,cat_id,goods_name,shop_price  from ecs_goods\r\n     where cat_id in (4,11);\r\n\r\n\r\n1.6:取出100<=价格<=500的商品(不许用and)\r\nselect goods_id,cat_id,goods_name,shop_price  from ecs_goods\r\n     where shop_price between 100 and 500;\r\n\r\n\r\n1.7:取出不属于第3栏目且不属于第11栏目的商品(and,或not in分别实现)\r\nselect goods_id,cat_id,goods_name,shop_price  from ecs_goods     where cat_id!=3 and cat_id!=11;\r\n\r\nselect goods_id,cat_id,goods_name,shop_price  from ecs_goods     where cat_id not in (3,11);\r\n\r\n\r\n\r\n1.8:取出价格大于100且小于300,或者大于4000且小于5000的商品()\r\nselect goods_id,cat_id,goods_name,shop_price  from ecs_goods where shop_price>100 and shop_price <300 or shop_price >4000 and shop_price <5000;\r\n\r\n\r\n\r\n1.9:取出第3个栏目下面价格<1000或>3000,并且点击量>5的系列商品\r\nselect goods_id,cat_id,goods_name,shop_price,click_count from ecs_goods where\r\ncat_id=3 and (shop_price <1000 or shop_price>3000) and click_count>5;\r\n\r\n1.10:取出第1个栏目下面的商品(注意:1栏目下面没商品,但其子栏目下有)\r\nselect goods_id,cat_id,goods_name,shop_price,click_count from ecs_goods\r\n     where cat_id in (2,3,4,5);\r\n\r\n1.11:取出名字以\"诺基亚\"开头的商品\r\nselect goods_id,cat_id,goods_name,shop_price  from ecs_goods     where goods_name like \'诺基亚%\';\r\n\r\n\r\n1.12:取出名字为\"诺基亚Nxx\"的手机\r\nselect goods_id,cat_id,goods_name,shop_price  from ecs_goods  \r\n   where goods_name like \'诺基亚N__\';\r\n\r\n\r\n1.13:取出名字不以\"诺基亚\"开头的商品\r\nselect goods_id,cat_id,goods_name,shop_price from ecs_goos\r\n     where goods_name not like \'诺基亚%\';\r\n\r\n1.14:取出第3个栏目下面价格在1000到3000之间,并且点击量>5 \"诺基亚\"开头的系列商品\r\nselect goods_id,cat_id,goods_name,shop_price  from ecs_goods where \r\ncat_id=3 and shop_price>1000 and shop_price <3000 and click_count>5 and goods_name like \'诺基亚%\';\r\n\r\n\r\nselect goods_id,cat_id,goods_name,shop_price  from ecs_goods where \r\nshop_price between 1000 and 3000 and cat_id=3  and click_count>5 and goods_name like \'诺基亚%\';\r\n\r\n\r\n1.15 一道面试题\r\n有如下表和数组\r\n把num值处于[20,29]之间,改为20\r\nnum值处于[30,39]之间的,改为30\r\n\r\nmian表\r\n+------+\r\n| num  |\r\n+------+\r\n|    3 |\r\n|   12 |\r\n|   15 |\r\n|   25 |\r\n|   23 |\r\n|   29 |\r\n|   34 |\r\n|   37 |\r\n|   32 |\r\n|   45 |\r\n|   48 |\r\n|   52 |\r\n+------+\r\n\r\n1.16 练习题:\r\n把good表中商品名为\'诺基亚xxxx\'的商品,改为\'HTCxxxx\',\r\n提示:大胆的把列看成变量,参与运算,甚至调用函数来处理 .\r\nsubstring(),concat()\r\n\r\n\r\n2	分组查询group:\r\n2.1:查出最贵的商品的价格\r\nselect max(shop_price) from ecs_goods;\r\n\r\n2.2:查出最大(最新)的商品编号\r\nselect max(goods_id) from ecs_goods;\r\n\r\n2.3:查出最便宜的商品的价格\r\nselect min(shop_price) from ecs_goods;\r\n\r\n2.4:查出最旧(最小)的商品编号\r\nselect min(goods_id) from ecs_goods;\r\n\r\n2.5:查询该店所有商品的库存总量\r\nselect sum(goods_number) from ecs_goods;\r\n\r\n2.6:查询所有商品的平均价\r\n select avg(shop_price) from ecs_goods;\r\n\r\n2.7:查询该店一共有多少种商品\r\n select count(*) from ecs_goods;\r\n\r\n\r\n2.8:查询每个栏目下面\r\n最贵商品价格\r\n最低商品价格\r\n商品平均价格\r\n商品库存量\r\n商品种类\r\n提示:(5个聚合函数,sum,avg,max,min,count与group综合运用)\r\nselect cat_id,max(shop_price) from ecs_goods  group by cat_id;\r\n\r\n\r\n3 having与group综合运用查询:\r\n3.1:查询该店的商品比市场价所节省的价格\r\nselect goods_id,goods_name,market_price-shop_price as j \r\n     from ecs_goods ;\r\n\r\n\r\n3.2:查询每个商品所积压的货款(提示:库存*单价)\r\nselect goods_id,goods_name,goods_number*shop_price  from ecs_goods\r\n\r\n3.3:查询该店积压的总货款\r\nselect sum(goods_number*shop_price) from ecs_goods;\r\n\r\n3.4:查询该店每个栏目下面积压的货款.\r\nselect cat_id,sum(goods_number*shop_price) as k from ecs_goods group by cat_id;\r\n\r\n3.5:查询比市场价省钱200元以上的商品及该商品所省的钱(where和having分别实现)\r\nselect goods_id,goods_name,market_price-shop_price  as k from ecs_goods\r\nwhere market_price-shop_price >200;\r\n\r\nselect goods_id,goods_name,market_price-shop_price  as k from ecs_goods\r\nhaving k >200;\r\n\r\n3.6:查询积压货款超过2W元的栏目,以及该栏目积压的货款\r\nselect cat_id,sum(goods_number*shop_price) as k from ecs_goods group by cat_id\r\nhaving k>20000\r\n\r\n3.7:where-having-group综合练习题\r\n有如下表及数据\r\n+------+---------+-------+\r\n| name | subject | score |\r\n+------+---------+-------+\r\n| 张三 | 数学    |    90 |\r\n| 张三 | 语文    |    50 |\r\n| 张三 | 地理    |    40 |\r\n| 李四 | 语文    |    55 |\r\n| 李四 | 政治    |    45 |\r\n| 王五 | 政治    |    30 |\r\n+------+---------+-------+\r\n\r\n要求:查询出2门及2门以上不及格者的平均成绩\r\n\r\n## 一种错误做法\r\nmysql> select name,count(score<60) as k,avg(score) from stu group by name having k>=2;\r\n+------+---+------------+\r\n| name | k | avg(score) |\r\n+------+---+------------+\r\n| 张三     | 3 |    60.0000 |\r\n| 李四     | 2 |    50.0000 |\r\n+------+---+------------+\r\n2 rows in set (0.00 sec)\r\n\r\nmysql> select name,count(score<60) as k,avg(score) from stu group by name;\r\n+------+---+------------+\r\n| name | k | avg(score) |\r\n+------+---+------------+\r\n| 张三     | 3 |    60.0000 |\r\n| 李四     | 2 |    50.0000 |\r\n| 王五     | 1 |    30.0000 |\r\n+------+---+------------+\r\n3 rows in set (0.00 sec)\r\n\r\nmysql> select name,count(score<60) as k,avg(score) from stu group by name having k>=2;\r\n+------+---+------------+\r\n| name | k | avg(score) |\r\n+------+---+------------+\r\n| 张三     | 3 |    60.0000 |\r\n| 李四     | 2 |    50.0000 |\r\n+------+---+------------+\r\n2 rows in set (0.00 sec)\r\n\r\n#加上赵六后错误暴露\r\nmysql> insert into stu \r\n    -> values \r\n    -> (\'赵六\',\'A\',100),\r\n    -> (\'赵六\',\'B\',99),\r\n    -> (\'赵六\',\'C\',98);\r\nQuery OK, 3 rows affected (0.05 sec)\r\nRecords: 3  Duplicates: 0  Warnings: 0\r\n\r\n#错误显现\r\nmysql> select name,count(score<60) as k,avg(score) from stu group by name having k>=2;\r\n+------+---+------------+\r\n| name | k | avg(score) |\r\n+------+---+------------+\r\n| 张三 | 3 |    60.0000 |\r\n| 李四 | 2 |    50.0000 |\r\n| 赵六 | 3 |    99.0000 |\r\n+------+---+------------+\r\n3 rows in set (0.00 sec)\r\n\r\n#正确思路,先查看每个人的平均成绩\r\nmysql> select name,avg(score) from stu group by name;\r\n+------+------------+\r\n| name | avg(score) |\r\n+------+------------+\r\n| 张三 |    60.0000 |\r\n| 李四 |    50.0000 |\r\n| 王五 |    30.0000 |\r\n| 赵六 |    99.0000 |\r\n+------+------------+\r\n4 rows in set (0.00 sec)\r\n\r\nmysql> # 看每个人挂科情况\r\nmysql> select name,score < 60 from stu;\r\n+------+------------+\r\n| name | score < 60 |\r\n+------+------------+\r\n| 张三 |          0 |\r\n| 张三 |          1 |\r\n| 张三 |          1 |\r\n| 李四 |          1 |\r\n| 李四 |          1 |\r\n| 王五 |          1 |\r\n| 赵六 |          0 |\r\n| 赵六 |          0 |\r\n| 赵六 |          0 |\r\n+------+------------+\r\n9 rows in set (0.00 sec)\r\n\r\nmysql> #计算每个人的挂科科目\r\nmysql> select name,sum(score < 60) from stu group by name;\r\n+------+-----------------+\r\n| name | sum(score < 60) |\r\n+------+-----------------+\r\n| 张三 |               2 |\r\n| 李四 |               2 |\r\n| 王五 |               1 |\r\n| 赵六 |               0 |\r\n+------+-----------------+\r\n4 rows in set (0.00 sec)\r\n\r\n#同时计算每人的平均分\r\nmysql> select name,sum(score < 60),avg(score) as pj from stu group by name;\r\n+------+-----------------+---------+\r\n| name | sum(score < 60) | pj      |\r\n+------+-----------------+---------+\r\n| 张三 |               2 | 60.0000 |\r\n| 李四 |               2 | 50.0000 |\r\n| 王五 |               1 | 30.0000 |\r\n| 赵六 |               0 | 99.0000 |\r\n+------+-----------------+---------+\r\n4 rows in set (0.00 sec)\r\n\r\n#利用having筛选挂科2门以上的.\r\nmysql> select name,sum(score < 60) as gk ,avg(score) as pj from stu group by name having gk >=2; \r\n+------+------+---------+\r\n| name | gk   | pj      |\r\n+------+------+---------+\r\n| 张三 |    2 | 60.0000 |\r\n| 李四 |    2 | 50.0000 |\r\n+------+------+---------+\r\n2 rows in set (0.00 sec)\r\n\r\n\r\n\r\n4:	order by 与 limit查询\r\n4.1:按价格由高到低排序\r\nselect goods_id,goods_name,shop_price from ecs_goods order by shop_price desc;\r\n\r\n4.2:按发布时间由早到晚排序\r\nselect goods_id,goods_name,add_time from ecs_goods order by add_time;\r\n\r\n4.3:接栏目由低到高排序,栏目内部按价格由高到低排序\r\nselect goods_id,cat_id,goods_name,shop_price from ecs_goods\r\n     order by cat_id ,shop_price desc;\r\n\r\n\r\n4.4:取出价格最高的前三名商品\r\nselect goods_id,goods_name,shop_price from ecs_goods order by shop_price desc limit 3;\r\n\r\n\r\n\r\n4.5:取出点击量前三名到前5名的商品\r\nselect goods_id,goods_name,click_count from ecs_goods order by click_count desc limit 2,3;\r\n\r\n5	连接查询\r\n5.1:取出所有商品的商品名,栏目名,价格\r\nselect goods_name,cat_name,shop_price from \r\necs_goods left join ecs_category\r\non ecs_goods.cat_id=ecs_category.cat_id;\r\n\r\n5.2:取出第4个栏目下的商品的商品名,栏目名,价格\r\nselect goods_name,cat_name,shop_price from \r\necs_goods left join ecs_category\r\non ecs_goods.cat_id=ecs_category.cat_id\r\nwhere ecs_goods.cat_id = 4;\r\n\r\n\r\n\r\n5.3:取出第4个栏目下的商品的商品名,栏目名,与品牌名\r\nselect goods_name,cat_name,brand_name from \r\necs_goods left join ecs_category\r\non ecs_goods.cat_id=ecs_category.cat_id\r\nleft join ecs_brand \r\non ecs_goods.brand_id=ecs_brand.brand_id\r\nwhere ecs_goods.cat_id = 4;\r\n\r\n5.4: 用友面试题\r\n\r\n根据给出的表结构按要求写出SQL语句。\r\nMatch 赛程表\r\n
    字段名称字段类型描述
    matchIDint主键
    hostTeamIDint主队的ID
    guestTeamIDint客队的ID
    matchResultvarchar(20)比赛结果,如(2:0)
    matchTimedate比赛开始时间
    \r\n\r\nTeam 参赛队伍表\r\n
    字段名称字段类型描述
    teamIDint主键
    teamNamevarchar(20)队伍名称
    \r\n\r\nMatch的hostTeamID与guestTeamID都与Team中的teamID关联\r\n查出 2006-6-1 到2006-7-1之间举行的所有比赛,并且用以下形式列出:\r\n拜仁 2:0 不来梅 2006-6-21\r\n\r\nmysql> select * from m;\r\n+-----+------+------+------+------------+\r\n| mid | hid | gid | mres | matime |\r\n+-----+------+------+------+------------+\r\n| 1 | 1 | 2 | 2:0 | 2006-05-21 |\r\n| 2 | 2 | 3 | 1:2 | 2006-06-21 |\r\n| 3 | 3 | 1 | 2:5 | 2006-06-25 |\r\n| 4 | 2 | 1 | 3:2 | 2006-07-21 |\r\n+-----+------+------+------+------------+\r\n4 rows in set (0.00 sec)\r\n\r\nmysql> select * from t;\r\n+------+----------+\r\n| tid | tname |\r\n+------+----------+\r\n| 1 | 国安 |\r\n| 2 | 申花 |\r\n| 3 | 公益联队 |\r\n+------+----------+\r\n3 rows in set (0.00 sec)\r\n\r\nmysql> select hid,t1.tname as hname ,mres,gid,t2.tname as gname,matime\r\n -> from \r\n -> m left join t as t1\r\n -> on m.hid = t1.tid\r\n -> left join t as t2\r\n -> on m.gid = t2.tid;\r\n+------+----------+------+------+----------+------------+\r\n| hid | hname | mres | gid | gname | matime |\r\n+------+----------+------+------+----------+------------+\r\n| 1 | 国安 | 2:0 | 2 | 申花 | 2006-05-21 |\r\n| 2 | 申花 | 1:2 | 3 | 公益联队 | 2006-06-21 |\r\n| 3 | 公益联队 | 2:5 | 1 | 国安 | 2006-06-25 |\r\n| 2 | 申花 | 3:2 | 1 | 国安 | 2006-07-21 |\r\n+------+----------+------+------+----------+------------+\r\n4 rows in set (0.00 sec)\r\n\r\n6 union查询\r\n6.1:把ecs_comment,ecs_feedback两个表中的数据,各取出4列,并把结果集union成一个结果集.\r\n\r\n6.2:3期学员碰到的一道面试题\r\nA表:\r\n+------+------+\r\n| id | num |\r\n+------+------+\r\n| a | 5 |\r\n| b | 10 |\r\n| c | 15 |\r\n| d | 10 |\r\n+------+------+\r\n\r\nB表:\r\n+------+------+\r\n| id | num |\r\n+------+------+\r\n| b | 5 |\r\n| c | 15 |\r\n| d | 20 |\r\n| e | 99 |\r\n+------+------+\r\n\r\n\r\n要求查询出以下效果:\r\n+------+----------+\r\n| id | num |\r\n+------+----------+\r\n| a | 5 |\r\n| b | 15 |\r\n| c | 30 |\r\n| d | 30 |\r\n| e | 99 |\r\n+------+----------+\r\n\r\ncreate table a (\r\nid char(1),\r\nnum int\r\n)engine myisam charset utf8;\r\n\r\ninsert into a values (\'a\',5),(\'b\',10),(\'c\',15),(\'d\',10);\r\n\r\ncreate table b (\r\nid char(1),\r\nnum int\r\n)engine myisam charset utf8;\r\n\r\ninsert into b values (\'b\',5),(\'c\',15),(\'d\',20),(\'e\',99);\r\n\r\n\r\nmysql> # 合并 ,注意all的作用\r\nmysql> select * from ta \r\n -> union all\r\n -> select * from tb;\r\n+------+------+\r\n| id | num |\r\n+------+------+\r\n| a | 5 |\r\n| b | 10 |\r\n| c | 15 |\r\n| d | 10 |\r\n| b | 5 |\r\n| c | 15 |\r\n| d | 20 |\r\n| e | 99 |\r\n+------+------+\r\n\r\n参考答案:\r\nmysql> # sum,group求和\r\nmysql> select id,sum(num) from (select * from ta union all select * from tb) as tmp group by id; \r\n+------+----------+\r\n| id | sum(num) |\r\n+------+----------+\r\n| a | 5 |\r\n| b | 15 |\r\n| c | 30 |\r\n| d | 30 |\r\n| e | 99 |\r\n+------+----------+\r\n5 rows in set (0.00 sec)\r\n\r\n\r\n7: 子查询:\r\n7.1:查询出最新一行商品(以商品编号最大为最新,用子查询实现)\r\nselect goods_id,goods_name from \r\n ecs_goods where goods_id =(select max(goods_id) from ecs_goods);\r\n\r\n\r\n7.2:查询出编号为19的商品的栏目名称(用左连接查询和子查询分别)\r\n7.3:用where型子查询把ecs_goods表中的每个栏目下面最新的商品取出来\r\nselect goods_id,goods_name,cat_id from ecs_goods where goods_id in (select max(goods_id) from ecs_goods group by cat_id);\r\n7.4:用from型子查询把ecs_goods表中的每个栏目下面最新的商品取出来\r\nselect * from (select goods_id,cat_id,goods_name from ecs_goods order by goods_id desc) as t group by cat_id;\r\n7.5 用exists型子查询,查出所有有商品的栏目\r\nselect * from category\r\nwhere exists (select * from goods where goods.cat_id=category.cat_id);\r\n\r\n\r\n创建触发器:\r\n\r\n CREATE trigger tg2\r\nafter insert on ord\r\nfor each row\r\nupdate goods set goods_number=goods_number-new.num where id=new.gid\r\n\r\nCREATE trigger tg3\r\nafter delete on ord\r\nfor each row\r\nupdate goods set goods_number=good_number+old.num where id=old.gid\r\n\r\n\r\nCREATE trigger tg4\r\nafter update on ord\r\nfor each row\r\nupdate goods set goods_number=goods_number+old.num-new.num where id=old.gid
    '); +INSERT INTO `ape_document_article` VALUES (34, '

    屏蔽h5 全屏按钮,经测试 默认 chrome 会出现 firefox和 360急速无 ,屏蔽后均没有了

    video::-webkit-media-controls-fullscreen-button {display: none;}

    屏蔽下载按钮

    video::-webkit-media-controls-enclosure {
        overflow:hidden;
    }
    video::-webkit-media-controls-panel {
         width: calc(100% + 30px); 
    }


    //去除右键事件
    $(\"video\").live(\"contextmenu\",function(){//取消右键事件
    return false;});
    '); +INSERT INTO `ape_document_article` VALUES (35, '

    相信很多人都会在手机端背景上花心思--因为图片适应了PC端,PE端效果就惨不忍睹。适应了PE端,PC端的背景单调的可怜,对于像西顾这种完美主义者来说,一看到这种丑八怪背景就想关站跑路了。

    例如,使用西顾图片APi就要判断用户来源是什么,根据判断来源调用西顾图片Api,则代码思路可以是:如果是手机端,则调用pc.png,否则调用pc.png。

    Advantage:图片调用更精准,减少PE端加载速度,背景恶心情况直接改变。

    话不多说,今天来演示下如何实现自判断访问是否为手机端来源。

     

    PHP如何实现自判断来源?

    方法一:

    判断HTTP_USER_AGENT
    $agent = strtolower($_SERVER[\'HTTP_USER_AGENT\']);\r\nif (strpos($agent, \"netfront\") || strpos($agent, \"iphone\") || strpos($agent, \"midp-2.0\") || strpos($agent, \"opera mini\") || strpos($agent, \"ucweb\") || strpos($agent, \"android\") || strpos($agent, \"windows ce\") || strpos($agent, \"symbianos\")) {\r\n    Header(\"HTTP/1.1 301 Moved Permanently\");\r\n    header(\"Location:####\");\r\n    die;\r\n}
    方法二:判断HTTP_ACCEPT

    if (isset($_SERVER[\'HTTP_ACCEPT\']) && (strpos($_SERVER[\'HTTP_ACCEPT\'], \'vnd.wap.wml\') !== FALSE) && (strpos($_SERVER[\'HTTP_ACCEPT\'], \'text/html\') === FALSE || (strpos($_SERVER[\'HTTP_ACCEPT\'], \'vnd.wap.wml\') < strpos($_SERVER[\'HTTP_ACCEPT\'], \'text/html\')))) {\r\n    //手机访问\r\n    Header(\"HTTP/1.1 301 Moved Permanently\");\r\n    header(\"Location:####\");\r\n    die;\r\n}\r\n

    更完美的骚操作:

    根据上述还有瑕疵的方法,往更高的层次着想:


    虽然还不是特别完善,但已经可以兼容十分多主流手机了。

    JS骚操作:

    /* ---示例代码----*/\r\nfunction echo (){    \r\n  var a=\"this is a example\";        \r\n  alert(\"hello world \"+a);\r\n}\r\n/* ---示例代码----*/
    好了,还有什么不懂的话,自己Google丰衣足食!
    '); +INSERT INTO `ape_document_article` VALUES (36, '

    今天在研究过程中,发现CSDN的这篇材料不错,就拿下来做Notes。

    第一步:在网页代码的头部,加入一行viewport元标签

    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />


    viewport是网页默认的宽度和高度,
    上面这行代码的意思是:网页宽度默认等于屏幕宽度(width=device-width),
    原始缩放比例(initial-scale=1)为1.0,即网页初始大小占屏幕面积的100%。

    所有主流浏览器都支持这个设置,包括IE9。对于那些老式浏览器(主要是IE6、7、8),需要使用css3-mediaqueries.js

    <!--[if lt IE 9]>\r\n    <script src=\"http://css3-mediaqueries-js.googlecode.com/svn/trunk/css3-mediaqueries.js\"></script>\r\n<![endif]-->


    第二步:(注意)不使用绝对宽度,字体大小

    width:auto; / width:XX%;


    第三步:(注意)字体大小

    字体大小是页面默认大小的100%,即16像素
    字体不要使用绝对大小\"PX\",要使用相对大小“REM”

    html{font-size:62.5%;}\r\nbody {font:normal 100% Arial,sans-serif;font-size:14px; font-size:1.4rem; }

    第四步:流动布局

    \"流动布局\"的含义是,各个区块的位置都是浮动的,不是固定不变的

    .left{ width:30%; float:left}\r\n.right{ width:70%; float:right;}

    其好处是,如果宽度太小,放不下两个元素,后面的元素会自动滚动到前面元素的下方,不会在水平方向overflow(溢出),避免了水平滚动条的出现

    第五步:选择加载CSS

    \"自适应网页设计\"的核心,就是CSS3引入的Media Query模块。自动探测屏幕宽度,然后加载相应的CSS文件

    <link rel=\"stylesheet\" type=\"text/css\" media=\"screen and (max-device-width: 600px)\"\r\nhref=\"style/css/css600.css\" />

    上面的代码意思是,如果屏幕宽度小于600像素(max-device-width: 600px),就加载css600.css文件。

    如果屏幕宽度在600像素到980像素之间,则加载css600-980.css文件

    <link rel=\"stylesheet\" type=\"text/css\" media=\"screen and (min-width: 600px) and (max-device-width: 980px)\"\r\nhref=\"css600-980.css\" />


    另有(不建议使用):除了用html标签加载CSS文件,还可以在现有CSS文件中加载

    @import url(\"css600.css\") screen and (max-device-width: 600px);

    第六步:CSS的@media规则

    @media screen and (max-device-width: 400px) {  .left{ float:none;} }

    当屏幕小于400时,left取消了浮动

    第七步:图片的自适应

    \"自适应网页设计\"还必须实现图片的自动缩放。

    img, object {max-width: 100%;}


    老版本的IE不支持max-width,所以只好写成:

    img {width: 100%;}


    windows平台缩放图片时,可能出现图像失真现象。这时,可以尝试使用IE的专有命令

    img { width:100%; -ms-interpolation-mode: bicubic;}


    或使用js--imgSizer.js

    addLoadEvent(function() {\r\n    var imgs = document.getElementById(\"content\").getElementsByTagName(\"img\");\r\n    imgSizer.collate(imgs);\r\n  });


    注:如有条件的话,最好还是根据不同大小的屏幕,加载不同分辨率的图片

    简易式操作:

    <html>\r\n<style type=\"text/css\">\r\nimg{ max-width:100%;}\r\nvideo{ max-width:100%; height:auto;}\r\nheader ul li{ float:left; list-style:none; list-style-type:none; margin-right:10px;}\r\nheader select{display:none;}\r\n@media (max-width:960px){\r\n    header ul{ display:none;}\r\n    header select{ display:inline-block;}\r\n}\r\n</style>\r\n<body>\r\n<header>\r\n<ul>\r\n<li><a href=\"#\" class=\"active\">Home</a></li>\r\n<li><a href=\"#\">AAA</a></li>\r\n<li><a href=\"#\">BBB</a></li>\r\n<li><a href=\"#\">CCC</a></li>\r\n<li><a href=\"#\">DDD</a></li>\r\n</ul>\r\n<select>\r\n<option class=\"selected\"><a href=\"#\">Home</a></option>\r\n<option value=\"/AAA\">AAA</option>\r\n<option value=\"/BBB\">BBB</option>\r\n<option value=\"/CCC\">CCC</option>\r\n<option value=\"/DDD\">DDD</option>\r\n</select>\r\n</header>\r\n</body>

    有什么不懂,自己格物致知!

    '); +INSERT INTO `ape_document_article` VALUES (37, '

    三个函数:

    addslashes($string):用反斜线引用字符串中的特殊字符\\\' \\\" \\\\

    $username=addslashes($username);

    mysql_escape_string($string):用反斜杠转义字符串中的特殊字符,用于mysql_query()查询。

    $username=mysql_escape_string($username);

    mysql_real_escape_string($string):转义SQL语句中使用的字符串中的特殊字符,并考虑到连接的当前字符集,需要保证当前是连接状态才能用该函数,否则会报警告。 不转义%与_

    $username=mysql_real_escape_string($username);

    两种选择:

    使用PDO

    $stmt = $pdo->prepare(\\\'SELECT * FROM user WHERE name = :name\\\');

    $stmt->execute(array(\\\':name\\\' => $name));

    foreach ($stmt as $row) {

    // do something with $row

    }

    使用mysqli

    $stmt = $dbConnection->prepare(\\\'SELECT * FROM user WHERE name = ?\\\');

    $stmt->bind_param(\\\'s\\\', $name);

    $stmt->execute();

    $result = $stmt->get_result();

    while ($row = $result->fetch_assoc()) {

    // do something with $row

    }

    '); +INSERT INTO `ape_document_article` VALUES (38, '

    packet main   //定义程序所属包

     

    import fmt  //导入依赖包

     

    //多个引入建议采取括号形式

    import {

    fmt

    time

    }

     

    const  name string =xxxx  //定义常量


    var  a  string = xxxx  //全局变量


    type 1223 int  //一般类型声明

     

    type learn struct {   

    //结构体声明

    }

     

    type llearn interface{

    //接口声明

    }

     

    func learn2(){

    //声明函数

    }

     

    //mian函数

    function main(){

    //入口函数

    }

     

     

    //文件必须拥有一个package声明,表示文件所属的代码包

     

    //要生成可执行程序,必须要有mainpackage,且必须在该包下面有main()函数

     

    同一个路径下只能存在一个package,一个package可以拆多个源文件

     

     

    ipmport原理

    \\\"图片1.png\\\" 


    先导入packet 1 >如果packet1中导入了packet2那么再导入pccket2 依次类推

     

    \\\"图片2.png\\\"

    import别名

     

    import 别名 原包名  在下面的语句中,原来的包名就变成了别名

     

    import bieming fmt  调用就可以  bieming.println()

     

    import . 别名   import .  包名  可以省略包名的前缀直接使用包内函数

     

    import .  fmt  调用 println()

     

    import _ xxx/  注册包引擎,方便我们的调用,只执行init函数,而不能调用其他函数

     

    数据类型

     

     \\\"图片3.png\\\"

    字符串和布尔

    \\\"图片4.png\\\" 

     

    整型

     

    整型  int8  int16 int32 int64

     

    无符号整型 在整型前面加个u  uint8  uint16 uint32 uint64

     

    注意:默认值为 0

     

    浮点型和复数

     

    float32  float64

     

    默认值为0

     

    复数 complex64  complex128

     

    默认值为 (0+0i)

     

    其他类型

     

    byte 类似uint8

     

    rune 类似 int32

     

    uint 32/64

     

    int uint 一样大

     

    uintptr 无符号整型  用于存放一个指针

     

    布尔类型

     

    Bool   True/false

     

    默认值为 false

     

     

    派生类型

     

    类型零值和类型别名

     

    类型所占存储大小

    '); +INSERT INTO `ape_document_article` VALUES (39, '

    布尔类型

    布尔类型  bool   true false\r\n\r\n

    数字类型

    数字类型\r\n\r\n整型 int \r\nint8 int16 int32 int64\r\n\r\n无符号整型uint   unsigned int\r\n\r\nuint8  uint16  uint32 uint64\r\n\r\n\r\n浮点型 float \r\n\r\nfloat32 float 64\r\n\r\n复合型complex  => float32*float32/float64*float64  同位数实数和虚数组成\r\n\r\ncomplex64 complex128\r\n\r\n\r\n其他数字类型\r\n\r\nbyte 类似 uint8\r\n\r\nrune 类似 int32\r\n\r\nuint 32 或 64 位\r\nint  与 uint 一样大小\r\n\r\n5uintptr无符号整型,无符号整型,用于存放一个指针

    字符串类型

    字符串 string\r\n\r\nvar str string //声明一个字符串\r\n

    派生类型


    指针

    指针   一个指针变量指向了一个值的内存地址\r\n\r\n声明方法  在类型前面加上 *\r\n\r\n访问指针变量中指向地址的值 变量前面+取地址符&   &变量\r\n\r\n空指针 当一个指针被定义后没有分配到任何变量时,它的值为 nil。\r\n\r\n\r\n例子:\r\n\r\nvar a int= 20   /* 声明实际变量 */\r\n\r\nvar ip *int        /* 声明指针变量 */\r\n\r\nip = &a  /* 指针变量的存储地址 */\r\n\r\n/*空指针*/\r\n\r\nvar  ptr *int\r\n\r\nfmt.Printf(\\\\\\\"ptr 的值为 : %x\\\\\\\\n\\\\\\\", ptr  )


    数组

    数组 相当于固定长度的php 有序数组\r\n\r\n声明   \r\nvar variable_name [SIZE] variable_type\r\nvar 数组名 [SIZE] 数组内变量类型\r\n\r\nvar  arr [5]float32{1000.0, 2.0, 3.4, 7.0, 50.0}


    结构体

    结构体 类似php的预先设置好属性的对象\r\n\r\n定义  结构体定义需要使用 type 和 struct 语句\r\n\r\ntype struct_variable_type struct {\r\n   member definition;\r\n   member definition;\r\n   ...\r\n   member definition;\r\n}\r\n\r\n声明结构体  var  结构体成员名  结构体类型\r\n\r\n例子:\r\n\r\ntype Books struct {\r\n   title string\r\n   author string\r\n   subject string\r\n   book_id int\r\n}\r\n\r\nfunc mian(){\r\n  var book1 Books\r\n}\r\n\r\n\r\n访问:  要访问结构体成员,需要使用点号 (.) 操作符\r\n\r\nstruct_variable_name.definition\r\n\r\n\r\n例子\r\n\r\npackage main\r\n\r\nimport \\\\\\\"fmt\\\\\\\"\r\n\r\ntype Books struct {\r\n   title string\r\n   author string\r\n   subject string\r\n   book_id int\r\n}\r\n\r\nfunc main() {\r\n   var Book1 Books        /* 声明 Book1 为 Books 类型 */\r\n   var Book2 Books        /* 声明 Book2 为 Books 类型 */\r\n\r\n   /* book 1 描述 */\r\n   Book1.title = \\\\\\\"Go 语言\\\\\\\"\r\n   Book1.author = \\\\\\\"www.runoob.com\\\\\\\"\r\n   Book1.subject = \\\\\\\"Go 语言教程\\\\\\\"\r\n   Book1.book_id = 6495407\r\n\r\n   /* book 2 描述 */\r\n   Book2.title = \\\\\\\"Python 教程\\\\\\\"\r\n   Book2.author = \\\\\\\"www.runoob.com\\\\\\\"\r\n   Book2.subject = \\\\\\\"Python 语言教程\\\\\\\"\r\n   Book2.book_id = 6495700\r\n\r\n   /* 打印 Book1 信息 */\r\n   fmt.Printf( \\\\\\\"Book 1 title : %s\\\\\\\\n\\\\\\\", Book1.title)\r\n   fmt.Printf( \\\\\\\"Book 1 author : %s\\\\\\\\n\\\\\\\", Book1.author)\r\n   fmt.Printf( \\\\\\\"Book 1 subject : %s\\\\\\\\n\\\\\\\", Book1.subject)\r\n   fmt.Printf( \\\\\\\"Book 1 book_id : %d\\\\\\\\n\\\\\\\", Book1.book_id)\r\n\r\n   /* 打印 Book2 信息 */\r\n   fmt.Printf( \\\\\\\"Book 2 title : %s\\\\\\\\n\\\\\\\", Book2.title)\r\n   fmt.Printf( \\\\\\\"Book 2 author : %s\\\\\\\\n\\\\\\\", Book2.author)\r\n   fmt.Printf( \\\\\\\"Book 2 subject : %s\\\\\\\\n\\\\\\\", Book2.subject)\r\n   fmt.Printf( \\\\\\\"Book 2 book_id : %d\\\\\\\\n\\\\\\\", Book2.book_id)\r\n}


    go语言函数

    Go 语言函数 没啥好解释都长这样就前缀 function=>func\r\n\r\nfunc function_name( [parameter list] ) [return_types] {\r\n   函数体\r\n}\r\n\r\nfunc  函数名 (参数列表) 返回类型{\r\n  函数体\r\n}\r\n\r\n


    Go 语言切片(Slice)

    Go 语言切片(Slice)\r\n\r\n不确定长度的数组就是切片\r\n\r\n声明   \r\nvar identifier []type \r\nvar 变量名 []类型 \r\n\r\n\r\n赋值 var 变量名 = []类型{值,值}\r\ns :=[] int {1,2,3 } \r\n\r\n\r\n切片不需要说明长度,或使用make()函数来创建切片:\r\nvar slice1 []type = make([]type, len) \r\n\r\n简写 slice1 := make([]type, len)\r\n\r\n也可以指定容量,其中capacity为可选参数\r\n\r\nmake([]T, length, capacity)


    Go 语言接口

    Go 语言接口\r\n都一样interface 声明就完事\r\n\r\n/* 定义接口 */\r\ntype interface_name interface {\r\n   method_name1 [return_type]\r\n   method_name2 [return_type]\r\n   method_name3 [return_type]\r\n   ...\r\n   method_namen [return_type]\r\n}\r\n\r\n/* 定义结构体 */\r\ntype struct_name struct {\r\n   /* variables */\r\n}\r\n\r\n/* 实现接口方法 */\r\nfunc (struct_name_variable struct_name) method_name1() [return_type] {\r\n   /* 方法实现 */\r\n}\r\n...\r\nfunc (struct_name_variable struct_name) method_namen() [return_type] {\r\n   /* 方法实现*/\r\n}


    Go 语言Map(集合)

    Go 语言Map(集合) 相当于 php的关联数组\r\n\r\nkey 类似于索引,指向数据的值。\r\n\r\n\r\n定义 Map\r\n可以使用内建函数 make 也可以使用 map 关键字来定义 Map:\r\n/* 声明变量,默认 map 是 nil */\r\nvar map_variable map[key_data_type]value_data_type\r\n\r\n/* 使用 make 函数 */\r\nmap_variable := make(map[key_data_type]value_data_type)\r\n\r\n\r\n例子\r\n\r\n\r\n   var countryCapitalMap map[string]string\r\n   /* 创建集合 */\r\n   countryCapitalMap = make(map[string]string)\r\n   \r\n   /* map 插入 key-value 对,各个国家对应的首都 */\r\n   countryCapitalMap[\\\\\\\"France\\\\\\\"] = \\\\\\\"Paris\\\\\\\"\r\n   countryCapitalMap[\\\\\\\"Italy\\\\\\\"] = \\\\\\\"Rome\\\\\\\"\r\n   countryCapitalMap[\\\\\\\"Japan\\\\\\\"] = \\\\\\\"Tokyo\\\\\\\"\r\n   countryCapitalMap[\\\\\\\"India\\\\\\\"] = \\\\\\\"New Delhi\\\\\\\"\r\n\r\n\r\n遍历 \r\n\r\n/* 使用 key 输出 map 值 */\r\n   for country := range countryCapitalMap {\r\n      fmt.Println(\\\\\\\"Capital of\\\\\\\",country,\\\\\\\"is\\\\\\\",countryCapitalMap[country])\r\n   }\r\n\r\n\r\n   \r\n   /* 查看元素在集合中是否存在 */\r\n   captial, ok := countryCapitalMap[\\\\\\\"United States\\\\\\\"]\r\n   /* 如果 ok 是 true, 则存在,否则不存在 */\r\n   if(ok){\r\n      fmt.Println(\\\\\\\"Capital of United States is\\\\\\\", captial)  \r\n   }else {\r\n      fmt.Println(\\\\\\\"Capital of United States is not present\\\\\\\") \r\n   }\r\n\r\n\r\ndelete() 函数\r\n\r\ndelete() 函数用于删除集合的元素, 参数为 map 和其对应的 key\r\ndelete(map,key);
    '); +INSERT INTO `ape_document_article` VALUES (40, '

    直接上程序


    <?php\r\n\r\n/** \r\n* for求一段数列的值\r\n* @param   $arr  有序数列\r\n* @return  int  sum\r\n**/ \r\nfunction foArrSum($arr){\r\n	if (!is_array($arr)) {\r\n		//先判断是不是数组\r\n		return 0;	\r\n	}\r\n\r\n	//开始for循环\r\n	$num = count($arr);\r\n	$sum = 0; //初始化$sum\r\n	for ($i=0; $i < $num; $i++) { \r\n		$sum += $arr[$i];\r\n	}\r\n\r\n	return $sum;\r\n}\r\n\r\n/**\r\n *	while求一段数列的值\r\n * 	@param   $arr 有序数列\r\n * 	@return int sum\r\n */\r\n\r\nfunction whileArrSum($arr){\r\n	if (!is_array($arr)) {\r\n		return 0;\r\n	}\r\n\r\n	//开始while循环\r\n	$num = count($arr);\r\n	$sum = 0; //初始化$sum\r\n	$i = 0; //初始化$i\r\n	while($i<$num){\r\n		$sum += $arr[$i];\r\n		$i++;\r\n	}\r\n\r\n	return $sum;\r\n}\r\n\r\n/**\r\n *	递归求一段数列的值\r\n * 	@param   $arr 有序数列\r\n * 	@return int sum\r\n */\r\n\r\nfunction  reaArrSum($arr,$i=0){\r\n	if (!is_array($arr)) {\r\n		return 0;\r\n	}\r\n\r\n	if ($i<count($arr)) {\r\n		return $arr[$i] + reaArrSum($arr,$i+1);\r\n	}\r\n}\r\n\r\n$arr=array(1,3,4,5,7);\r\necho foArrSum($arr);\r\necho whileArrSum($arr);\r\necho reaArrSum($arr);
    '); +INSERT INTO `ape_document_article` VALUES (41, '

    斐波那契数列

    又称兔子数列,或者黄金分割数列。指的是这样一个数列:

    0、1、1、2、3、5、8、13、21……从第三项起,它的每一项都等于前两项的和。

    <?php\r\n\r\n/** \r\n* php实现斐波那契数列\r\n* @param   $num  输出多少个\r\n* @return  int  sum\r\n**/ \r\nfunction fbList($num){\r\n	if ($num<0) {\r\n		return -1;\r\n	}\r\n	$arr = array();\r\n	for ($i=0; $i < $num; $i++) { \r\n		if ($i<2) {\r\n			$arr[$i] = $i;\r\n		}else{\r\n			(float)$arr[$i] = (float)$arr[$i-1] + (float)$arr[$i-2];\r\n		}\r\n		echo $arr[$i].\\\'</br>\\\';\r\n	}\r\n	\r\n	return implode(\\\' \\\', $arr);\r\n}\r\n\r\necho fbList(100);


    别问我为啥 float 毕竟默认int 位数溢出伤不起  

    '); +INSERT INTO `ape_document_article` VALUES (42, '

    转换很简单

    type_name(expression)\r\n\r\n直接把 变量 用要转换的的类型  当做方法包裹起来\r\n\r\n例子:\r\nvar num int = 10\r\nfloat(num)
    '); +INSERT INTO `ape_document_article` VALUES (43, '

    问题描述:

    随机拿出一个0到100的数,让用户猜,每次猜大了或猜小了,都要给出提示,最后给出正确答案,最少要多少次

    /** \r\n*  php随机取一个数字(0-100)猜是多少\r\n* @param   $min  开始值\r\n* @param   $max  结束值 \r\n* @param   $time 循环次数\r\n* @return  int  sum\r\n**/ \r\nfunction guessNum($num,$min=0,$max=100,$time=0){\r\n	$gnum = ceil(($max+$min)/2);//猜想数为最大数和最小数的1/2进一取整\r\n	$time += 1;\r\n	if ($num!=$gnum) {\r\n		if($num < $gnum){\r\n			$max = $gnum;\r\n		}else{\r\n			$min = $gnum;\r\n		}\r\n		$time=guessNum($num,$min,$max,$time);\r\n	}\r\n	return $time;\r\n}\r\necho guessNum(5);
    '); +INSERT INTO `ape_document_article` VALUES (44, '

    问题   as 别名   where 别名为什么提示 别名不存在?

    先看语句       

    select goods_id,goods_name,(market_price-shop_price) as k from goods where k>0; 

    解释:查询模型决定的


    mysql 查询模型   先去匹配  where 也就是 where后面的变量寻址 然后再来 筛选后面的显示 行,由于先去匹配别名所以别名找不到.但是这样就说别名没用了 ,不可能

    having 可以用啊!!!!!! 

    having是后筛选的,先查出结果,然后having执行进一步筛选

    select goods_id,goods_name,(market_price-shop_price) as k from goods having k>0; 

    这样就可以了!!!

    '); +INSERT INTO `ape_document_article` VALUES (45, '

    接口

    定义: 

    interface  接口名{

    public function  方法名();

    }

    class  类名 implement  接口名{

    public function 方法名(){

    //和接口中的一致

    }

    }

    接口实例

    <?php\r\ninterface People{\r\npublic function eat();\r\npublic function sleep();\r\n}\r\nclass Man implements People{\r\npublic function eat(){\r\necho \'吃吃吃次\';\r\n}\r\npublic function sleep(){\r\necho \'睡睡睡\';\r\n}\r\n}\r\nclass L{\r\npublic static function factory (People $user){\r\nreturn $user;\r\n}\r\n}\r\n$user=L::factory(new Man());\r\n$user->eat();\r\n$user->sleep();


    抽象类

    abstrct class 类名{

    public function 方法名(){

    }

    }

    class test extends 类名(){

    $this->抽象类方法();

    }


    区别

    '); +INSERT INTO `ape_document_article` VALUES (46, '

    在header头所有引用开始的地方加上 base 标签可以解决引用路径的问题

    \"QQ图片20180427152752.png\"


    <base href=\"http://127.0.0.1/\" /> 

    后面引入直接写相对路径即可

    例如

    http://127.0.0.1/static/bootstrap/css/bootstrap.min.css

    就直接写

    <link rel=\"stylesheet\" type=\"text/css\" href=\"static/bootstrap/css/bootstrap.min.css\">
    '); +INSERT INTO `ape_document_article` VALUES (47, '

    ctrl+h打开替换面板

    选择正则表达式

    输入

    \\/\\*tpa=h[^\"]* */

    替换为空即可

    \"QQ图片20180428175843.png\"

    '); +INSERT INTO `ape_document_article` VALUES (48, '


    header(\'content-type:text/html; charset=utf-8\');\r\n$stratTime = microtime(true);\r\n$startMemory = memory_get_usage();\r\n\r\n\r\n$endTime = microtime(true);\r\n$runtime = ($endTime - $stratTime) * 1000; //将时间转换为毫秒\r\n$endMemory = memory_get_usage();\r\n$usedMemory = ($endMemory - $startMemory) / 1024;\r\necho \"运行时间: {$runtime} 毫秒
    \";\r\necho \"耗费内存: {$usedMemory} K\";\r\ndie();
    '); +INSERT INTO `ape_document_article` VALUES (49, '

    实验

    首先,设置一个Cookie

    <?php  

    setcookie(\'\',\'aaa\',time()+3600,\'/\');

    echo $_COOKIE[\'a\']; 

    ?> 

    下面我们来看看,当首次(当前页面)访问此页面时,会报错:


    \"微信图片_20190801103719.png\"

    分析

    那么为什么会报Undefined错误呢

    ①首次访问【未刷新】

    我们来看看首次访问时页面响应头信息,发现

    [响应头信息]中增加Set-Coookie参数,但[请求头信息]中没有Cookie参数

    ②>1次访问[刷新过]

    我们来看第二次访问时页面显示结果:


    \"微信图片_20190801103443.png\"

    发现Cookie的值显示在了页面上。这时我们再来看看[响应头]和[请求头]信息,此时请求头信息中多了参数Cookie

    总结Cookie设置生效过程

    当我们首次访问设置Cookie的页面时,服务器会把设置的Cookie值通过响应头发送过来,告诉浏览器将cookie存储的本地相应文件夹中(注意:第一次访问时本地还没有存储Cookie,所以此时获取不到值);

    当第二次访问(或在进行cookie设置后,过期前所有的访问)时,请求头信息你中都会把Cookie值携带。

    下面用图片更加形象的演示Cookie设置生效过程


    \"20171110195541080.png\"

    '); +INSERT INTO `ape_document_article` VALUES (50, '

    为什么慢

    由于默认情况下执行 composer 各种命令是去国外的 composer 官方镜像源获取需要安装的具体软件信息,所以在不使用代理、不翻墙的情况下,从国内访问国外服务器的速度相对比较慢

    如何修改镜像源

    可以使用阿里巴巴提供的 Composer 全量镜像 https://mirrors.aliyun.com/composer/

    a). 配置只在当前项目生效

    composer config repo.packagist composer https://mirrors.aliyun.com/composer/\r\n\r\n# 取消当前项目配置\r\ncomposer config --unset repos.packagist

    b). 配置全局生效

    composer config -g repo.packagist composer https://mirrors.aliyun.com/composer/\r\n\r\n# 取消全局配置\r\ncomposer config -g --unset repos.packagist

    c). 使用第三方软件快速修改、切换 composer 镜像源

    crm composer registry manager

    安装 crm
    composer global require slince/composer-registry-manager
    列出可用的所有镜像源,前面带 * 代表当前使用的镜像
    composer repo:ls\r\n\r\n-- --------------- ------------------------------------------------\r\n     composer        https://packagist.org\r\n     phpcomposer     https://packagist.phpcomposer.com\r\n     aliyun          https://mirrors.aliyun.com/composer\r\n     tencent         https://mirrors.cloud.tencent.com/composer\r\n     huawei          https://mirrors.huaweicloud.com/repository/php\r\n     laravel-china   https://packagist.laravel-china.org\r\n     cnpkg           https://php.cnpkg.org\r\n     sjtug           https://packagist.mirrors.sjtug.sjtu.edu.cn\r\n-- --------------- ------------------------------------------------
    使用 aliyun 镜像源
    composer repo:use aliyun\r\n\r\n# 执行成功之后会输出类似以下信息\r\n[OK] Use the repository [aliyun] success
    再次执行 composer repo:ls 命令,看到前面带 * 的就是当前使用的镜像
    composer repo:ls\r\n\r\n# 可以看到 aliyun 前面有一个 * 号,代表当前使用的是 aliyun 的源\r\n--- --------------- ------------------------------------------------\r\n      composer        https://packagist.org\r\n      phpcomposer     https://packagist.phpcomposer.com\r\n  *   aliyun          https://mirrors.aliyun.com/composer\r\n      tencent         https://mirrors.cloud.tencent.com/composer\r\n      huawei          https://mirrors.huaweicloud.com/repository/php\r\n      laravel-china   https://packagist.laravel-china.org\r\n      cnpkg           https://php.cnpkg.org\r\n      sjtug           https://packagist.mirrors.sjtug.sjtu.edu.cn\r\n--- --------------- ------------------------------------------------

    更多用法查看 crm GitHub

    '); +INSERT INTO `ape_document_article` VALUES (51, '
    使用方法: \r\nhttps://cdn.yangju.vip/k/?url=后面加上播放的地址即可\r\nhttp://okjx.cc/?url=\r\nhttps://vip.bljiex.com/?v=\r\nhttp://ok.jlsprh.com/g/?url=\r\nhttps://cdn.yangju.vip/k/?url=\r\nhttps://jx.lache.me/cc/?url=\r\nhttps://api.653520.top/vip/?url=\r\nhttps://jx.ab33.top/vip/?url=\r\nhttps://vip.mpos.ren/v/?url=\r\nhttps://jx.000180.top/jx/?url=\r\nhttps://jx.km58.top/jx/?url=\r\nhttp://p.p40.top/?v=\r\nhttp://jiexi.071811.cc/jx2.php?url=\r\nhttp://jqaaa.com/jq3/?url=\r\nhttps://www.douban888.com/m3u8.php?url=\r\nhttp://www.600m.net/api/?v=  \r\nhttps://z1.m1907.cn/?jx=  \r\nhttps://www.8090g.cn/?url=\r\nhttp://jiexi.92fz.cn/player/vip.php?url=\r\nhttp://www.3aym.cn/?url=\r\nhttp://jx.x-99.cn/jx7.php?id=\r\nhttp://17kyun.com/api.php?url=\r\nhttps://www.administratorw.com/admin.php?url=\r\nhttp://tv.x-99.cn/api/wnapi.php?id=\r\nhttp://cs.drgxj.com/?url=\r\nhttp://jx.du2.cc/?url=\r\nhttp://jx.618ge.com/jx/9.php?url=\r\nhttp://vip.jlsprh.com/?url=\r\nhttp://jx.598110.com/?url=\r\nhttp://jx.598110.com/v/2.php?url=\r\nhttps://www.1717yun.com/jx/ty.php?url=\r\nhttp://www.1717yun.com/jx/ty.php?url=\r\nhttp://jx.drgxj.com/?url=\r\nhttp://jx.618ge.com/?url=\r\nhttp://vip.jlsprh.com/?url=\r\nhttp://jx.598110.com/?url=\r\nhttp://www.vipjiexi.com/tong.php?url=\r\nhttp://www.wmxz.wang/video.php?url=\r\nhttp://api.baiyug.vip/index.php?url=\r\nhttp://v.d9y.net/vip/?url=\r\nhttp://jx.du2.cc/?url=\r\n\r\n
    (含第三方广告)\r\nhttp://jiexi.071811.cc/jx2.php?url=\r\nhttp://app.baiyug.cn:2019/vip/?url=\r\nhttp://tv.beipy.com/jx/?url=\r\nhttp://api.nepian.com/ckparse/?url=\r\nhttp://j.zz22x.com/jx/?url=\r\nhttp://api.wlzhan.com/sudu/?url=\r\nhttp://jqaaa.com/jq3/?url=\r\nhttp://aikan-tv.com/?url=

    **全网解析接口  来自Typecho ***\r\n
    全网解析 https://www.cuan.la/?url= (全网解析都支持,包括VIP资源,第三方切片资源)\r\nP2P以开始全面收费,不想花钱的使用以下接口即可:\r\nP2P版M3U8资源专属解析(国内口):https://www.xmaocloud.com/m3u8.php?url=\r\nP2P版M3U8资源专属解析(国外口):https://www.629055.com/m3u8.php?url=\r\nhttps://www.kkflv.com/index.php?url=

    ⑤号通用vip引擎系统【稳定通用 http://jx.du2.cc/?url=\r\n④号通用vip引擎系统【超级稳定通用】http://jx.drgxj.com/?url=\r\n③号通用vip引擎系统【稳定通用】http://jx.618ge.com/?url=\r\n②号通用vip引擎系统【稳定通用】 http://vip.jlsprh.com/?url=\r\n①号通用vip引擎系统【稳定通用】 http://jx.598110.com/?url=\r\n\r\nhttp://www.506060.com/jx/?url=\r\nhttp://api.3jx.top/vip/?url=\r\nhttps://www.nxflv.com/?url=\r\nhttps://jx.688ing.com/?search=\r\nhttp://jx.598110.com/?url=\r\nhttp://jx.598110.com/?url=\r\nhttp://jqaaa.com/jq3/?url=\r\nhttps://www.1717yun.com/jx/ty.php?url=\r\nhttps://play.7nmg.net/?v=\r\nhttp://jqaaa.com/jx.php?url=
    /*\r\n\r\n*需要自己提供解析接口,在百度搜索[vip解析]\r\n\r\n*说明[最多6条]:格式[@01=\"http://jx.xxxxxx.com/?url=\"]\r\n\r\n*说明2:把解析地址添加到下面格式的双引号中[@01=\"\"]\r\n\r\n*/\r\n\r\n\r\n\r\niqiyi={\r\n\r\n@01=\"https://660e.com/?url=\"\r\n\r\n@01=\"http://jx.mdai52.top/vip/?url=\"\r\n\r\n@01=\"http://jx.618g.com/?url=\"\r\n\r\n@01=\"http://www.27v9.cn/index.php?url=\"\r\n\r\n@01=\"https://660e.com/?url=\"\r\n\r\n@01=\"http://api.xyingyu.com/?url=\"\r\n\r\n};\r\n\r\n\r\n\r\nqq={\r\n\r\n@01=\"https://660e.com/?url=\"\r\n\r\n@01=\"http://jx.mdai52.top/vip/?url=\"\r\n\r\n@01=\"http://jx.618g.com/?url=\"\r\n\r\n@01=\"http://www.27v9.cn/index.php?url=\"\r\n\r\n@01=\"https://660e.com/?url=\"\r\n\r\n@01=\"http://api.xyingyu.com/?url=\"\r\n\r\n};\r\n\r\n\r\n\r\nmgtv={\r\n\r\n@01=\"https://660e.com/?url=\"\r\n\r\n@01=\"http://jx.mdai52.top/vip/?url=\"\r\n\r\n@01=\"http://jx.618g.com/?url=\"\r\n\r\n@01=\"http://www.27v9.cn/index.php?url=\"\r\n\r\n@01=\"https://660e.com/?url=\"\r\n\r\n@01=\"http://api.xyingyu.com/?url=\"\r\n\r\n};\r\n\r\n\r\n\r\nletv={\r\n\r\n@01=\"https://660e.com/?url=\"\r\n\r\n@01=\"http://jx.mdai52.top/vip/?url=\"\r\n\r\n@01=\"http://jx.618g.com/?url=\"\r\n\r\n@01=\"http://www.27v9.cn/index.php?url=\"\r\n\r\n@01=\"https://660e.com/?url=\"\r\n\r\n@01=\"http://api.xyingyu.com/?url=\"\r\n\r\n};\r\n\r\n\r\n\r\nyouku={\r\n\r\n@01=\"https://660e.com/?url=\"\r\n\r\n@01=\"http://jx.mdai52.top/vip/?url=\"\r\n\r\n@01=\"http://jx.618g.com/?url=\"\r\n\r\n@01=\"http://www.27v9.cn/index.php?url=\"\r\n\r\n@01=\"https://660e.com/?url=\"\r\n\r\n@01=\"http://api.xyingyu.com/?url=\"\r\n\r\n};\r\n\r\n\r\n\r\nsohu={\r\n\r\n@01=\"https://660e.com/?url=\"\r\n\r\n@01=\"http://jx.mdai52.top/vip/?url=\"\r\n\r\n@01=\"http://jx.618g.com/?url=\"\r\n\r\n@01=\"http://www.27v9.cn/index.php?url=\"\r\n\r\n@01=\"https://660e.com/?url=\"\r\n\r\n@01=\"http://api.xyingyu.com/?url=\"\r\n\r\n};\r\n\r\n\r\n\r\n
    '); +INSERT INTO `ape_document_article` VALUES (52, '

    将地址自动转换,关联时候有些为子剧集第一集,关联会出现错误,所以转换为父剧集

    $url = \"http://v.youku.com/v_show/id_XMzg3ODI3OTI4NA==.html\";
    var_dump(urlCover($url,\'youku\'));

    /** 获取META信息 */
    function urlCover($url,$site)
    {
    /*简单处理*/
    if ($site == \'iqiyi\'){
    return $url;
    }
    if (str_replace(\'http://so.iqiyi.com/links\',\'\',$url) != $url) {
    $data = file_get_contents($url);
    preg_match(\'/<META\\s+http-equiv=\"refresh\"\\s+content=\"0;URL=\\\'([\\w\\W]*?)\"/si\', $data, $matches);
    if (!empty($matches[1])) {
    $url = substr($matches[1],0,-1);
    }
    }
    switch ($site){
    case \'qq\':
    if (strpos($url,\'?ptag=iqiyi\')){
    $url = substr($url,0,strpos($url,\'?ptag=iqiyi\'));
    }
    if (strpos($url,\'film.qq.com\')){
    $url = str_replace(\'http://film.qq.com/cover/\',\'https://v.qq.com/detail/\',$url);
    }
    //通过子剧集获取视频连接
    $html=file_get_contents($url);
    $dom = new DOMDocument();
    //从一个字符串加载HTML
    @$dom->loadHTML($html);
    //使该HTML规范化
    $dom->normalize();
    //用DOMXpath加载DOM,用于查询
    $xpath = new DOMXPath($dom);
    #获取播放器播放标题的a标签的地址
    $hrefs = $xpath->query(\"//*[@id=\\\"container_player\\\"]/div/div[1]/div[2]/div[2]/div[1]/div[1]/div[1]/h2/a//@href\");
    for ($i = 0; $i < $hrefs->length; $i++) {
    $href = $hrefs->item($i);
    $linktext = $href->nodeValue;
    $url = \'https://v.qq.com\'.$linktext;
    break;
    }
    break;
    case \'youku\':
    //通过子剧集获取视频连接
    $html=file_get_contents($url);
    $dom = new DOMDocument();
    //从一个字符串加载HTML
    @$dom->loadHTML($html);
    //使该HTML规范化
    $dom->normalize();
    //用DOMXpath加载DOM,用于查询
    $xpath = new DOMXPath($dom);
    #获取播放器播放标题的a标签的地址
    $hrefs = $xpath->query(\" //*[@class=\\\"tvinfo\\\"]/h2/a//@href\");
    for ($i = 0; $i < $hrefs->length; $i++) {
    $href = $hrefs->item($i);
    $linktext = $href->nodeValue;
    $url = \'https:\'.$linktext;
    break;
    }
    break;
    /*其他等需要的时候再行适配,imgo不需要适配连接正确*/
    default:
    break;
    }
    return $url;
    }
    '); +INSERT INTO `ape_document_article` VALUES (53, '

    网站升级https协议。

    在 HTTPS 承载的页面上不允许出现 http 请求,一旦出现就是提示或报错:

    Mixed Content: The page at \'https://www.example.com\' was loaded over HTTPS, \r\nbut requested an insecure image ‘http://static.example.com/test.jpg’. \r\nThis content should also be served over HTTPS.

    因此即使使用到的域名对http请求已经强制了https,但是在页面中浏览器对于http请求压根就不会发送,那么就必需替换页面上所有的http为https,而我遇到的是个使用了十年的老系统,代码中有很多硬编码的http地址,一一替换的话要替换2万多行。。

    于是从http协议入手,在响应header中添加upgrade-insecure-requests,即在php入口文件中添加:

    header(\"Content-Security-Policy: upgrade-insecure-requests\");

    或着也可以在由前端在html页面中添加meta:

    <meta http-equiv=\"Content-Security-Policy\" content=\"upgrade-insecure-requests\" />

    或者在nginx配置中进行header的添加

    server {\r\n        listen       443;\r\n        server_name  www.example.com;\r\n        error_log  /logs/nginx/error.log;\r\n        root /var/www/www.example.com;\r\n        index  index.php index.html index.htm;\r\n        ssl on;\r\n        ssl_certificate   cert/test/test.pem;\r\n        ssl_certificate_key  cert/test/test.key;\r\n        ssl_session_timeout 5m;\r\n     \r\n     	#添加响应头\r\n        add_header Content-Security-Policy \"upgrade-insecure-requests\'\";\r\n        location / {\r\n                if (!-f $request_filename){\r\n                        rewrite ^/(.*)$ /index.php?s=$1 last;\r\n                        break;\r\n                }\r\n                limit_except GET POST DELETE PUT {\r\n                        deny all;\r\n                }\r\n        }\r\n……\r\n}

    从而让浏览器对页面中的所有http请求,都升级为https协议发送请求,从而省去了逐一修改url的协议的麻烦。

    '); +INSERT INTO `ape_document_article` VALUES (54, '

    linux杀死相关所有进程

     ps -ef|grep chrome|grep -v grep|cut -c 9-15|xargs kill -9

    chrome修改你要杀死的进程

    '); +INSERT INTO `ape_document_article` VALUES (55, '

    1、查看系统是否有僵尸进程

    \"\"\"20150107164521516.png\"

    使用Top命令查找,当zombie前的数量不为0时,即系统内存在相应数量的僵尸进程。

    2、定位僵尸进程

    使用命令 定位僵尸进程以及该僵尸进程的父进程

    ps -A -ostat,ppid,pid,cmd |grep -e \'^[Zz]\'

    \"\"\"20150107164805082.png\"

    僵尸进程ID:3457,父进程ID:3425

    僵尸进程ID:3533,父进程ID:3511

    3、使用Kill -HUP 僵尸进程ID来杀死僵尸进程,往往此种情况无法杀死僵尸进程,此时就需要杀死僵尸进程的父进程

    kill -HUP 僵尸进程父ID

    \"\"\"20150107165046527.png\"

    然后使用上面的语句查询该僵尸进程是否被杀死

    \"\"\"20150107165055828.png\"

    4、参数解读

    ps -A -ostat,ppid,pid,cmd |grep -e \'^[Zz]\'

    -A  参数列出所有进程

    -o  自定义输出字段 stat(状态)、ppid(进程父id)、pid(进程id)、cmd(命令)

    因为状态为z或者Z的进程为僵尸进程,所以我们使用grep抓取stat状态为zZ进程

    5 快速杀死所有僵尸进程命令

    ps -A -o stat,ppid,pid,cmd | grep -e \'^[Zz]\' | awk \'{print $2}\' | xargs kill -9
    '); +INSERT INTO `ape_document_article` VALUES (56, '

    运行环境

    php 7.1 ++

    queryList 4.0.4 


    <?php\r\nfunction index()\r\n    {\r\n        $url = \'https://list.youku.com/category/show/c_97.html\';\r\n        //采集规则\r\n        $rules = [\r\n            //视频标题\r\n            \'title\' => [\'.info-list .title\',\'text\'],\r\n            //视频连接\r\n            \'link\' => [\'.p-thumb>a\',\'href\'],\r\n            //视频图片\r\n            \'img\' => [\'.p-thumb>img\',\'src\'],\r\n            //视频右下角\r\n            \'rb\' => [\'.p-info>li>span>span\',\'text\'],\r\n            //演员\r\n            \'actor\'=>[\'.actor\',\'html\',\'\',function($content){\r\n                $content = QueryList::html($content)->find(\'a\')->texts()->all();\r\n                $content =implode(\',\',$content);\r\n                return $content;\r\n            }],\r\n            //最近更新\r\n            \'last_update_at\'=>[\'.info-list>li:last\',\'text\'],\r\n        ];\r\n        // 4.0.4 ++语法\r\n        $data = QueryList::get($url)->rules($rules)->queryData();\r\n        //4.0.4 以下\r\n//        $data = QueryList::get($url)->rules($rules)->query()->getData()->all();\r\n        var_dump($data);\r\n    }\r\n?>
    '); +INSERT INTO `ape_document_article` VALUES (57, '

    1.下载

    激活的版本2019.1.2,PhpStorm-2019.1.2可以用官网版本

    当然可以从官网获取,也可以从下面的获取。

    PhpStorm-2019.1.2.dmg

    https://u1826018.ctfile.com/fs/1826018-387345410

    下载激活用的jar包 jetbrains-agent.jar

    下载地址:

    https://u1826018.ctfile.com/fs/1826018-387181004

    文件下载完成之后,安装PhpStorm,然后打开试用,之后任意创建一个项目。

    2.激活

    将下载好的jetbrains-agent.jar移动到然后,把这个文件放入安装phpstorm/contents/lib目录下,

    安装完之后,打开了PhpStorm,点击菜单\"Help\"—>“Edit Custom VM Options…”,

    打开文件之后,在末尾添加一行参数,指向激活用的jar包的地址。

    绝对路径

    -javaagent:/Applications/PhpStorm.app/Contents/lib/jetbrains-agent.jar

    要是你安装文件包的绝对路径

    相对路径

    windows版:-javaagent:D:/indea/lib/jetbrains-agent.jar

    Mac版:-javaagent:../lib/Jjetbrains-agent.jar

    添加完之后,保存,然后退出,重启PhpStorm。

    3、最后一步

    重启完成之后,复制

    http://jetbrains-license-server

    执行菜单\"Help\"-——>“Register”,打开注册框,选择\"License server\"方式,粘贴,点击Activate激活

    试用可用的注册码,进行激活就可以了。

    到此,激活完成

    '); +INSERT INTO `ape_document_article` VALUES (58, '

    在工作中,我们经常会发现表中会存在重复数据,那么如何找出和删除这些数据呢?

    下面,以一个小例子来说明:

    1、创建学生表

    1 CREATE TABLE student(\r\n2     id INT PRIMARY KEY,\r\n3     stuno VARCHAR(12) NOT NULL,\r\n4     stuname VARCHAR(30) NOT null\r\n5 );

    2、向学生表中插入数据

    \"复制代码\"

    1 INSERT INTO student VALUES (\'1\',\'131111099\',\'小李\');\r\n2 INSERT INTO student VALUES (\'2\',\'131111100\',\'小陈\');\r\n3 INSERT INTO student VALUES (\'3\',\'131111101\',\'小王\');\r\n4 INSERT INTO student VALUES (\'4\',\'131111102\',\'小黑\');\r\n5 INSERT INTO student VALUES (\'5\',\'131111099\',\'小曹\');\r\n6 INSERT INTO student VALUES (\'6\',\'131111099\',\'小李\');

    \"复制代码\"

    3、查找仅学号重复的记录

     从插入记录上看,id为1、5、6的记录学号都是相同的,那么验证一下查询的数据是否正确

    \"复制代码\"

    1 -- 学号重复\r\n2 -- 先按学号进行分组,然后查询学数量 > 1的记录的学号\r\n3 SELECT * FROM student WHERE stuno IN (\r\n4     -- 查找重复的学号\r\n5     SELECT stuno FROM student GROUP BY stuno HAVING COUNT(stuno) > 1\r\n6 );

    \"复制代码\"

    查询结果如下:

    \"\"

    查询结果和我们事先分析的数据一致,所以查询结果是正确的。

    4、查找学号和姓名均重复的记录

    从插入记录上看,只有id为1、6的记录学号和姓名是完全重复的,那么验证一下查询的数据是否正确

    按 Ctrl+C 复制代码

    按 Ctrl+C 复制代码

    查询结果如下:

    \"\"

    查询结果和我们事先分析的数据一致,所以查询结果是正确的。

    5、删除多余的重复记录(多个字段),只保留最小id的记录

    重复记录可能有多条,但是我们只希望保留id最小的那条记录,因为学号和姓名均重复的只有id为1、6的记录,保留id为1的记录,那么验证一下查询的数据是否正确

    按 Ctrl+C 复制代码

    按 Ctrl+C 复制代码

    查询结果如下:

    \"\"

    可以看出,id为6的记录已经被删除了,所以结果正确

    警告:不能根据本表的查询结果来更新本表的数据

    在其它的帖子中有看到如下写法来删除重复数据:

    \"复制代码\"

    1 DELETE FROM student WHERE (stuno,stuname) -- 注意:此处一定要加括号,当成联合字段来处理\r\n2     IN (\r\n3         -- 查找学号和姓名均重复的学生信息\r\n4         SELECT stuno,stuname FROM student GROUP BY stuno,stuname HAVING COUNT(1) > 1\r\n5     ) AND id NOT IN (\r\n6         -- 查询最小id的记录\r\n7         SELECT MIN(id) FROM student GROUP BY stuno,stuname HAVING COUNT(1) > 1\r\n8 );

    \"复制代码\"

    会报如下错误:

      [Err] 1093 - You can\'t specify target table \'student\' for update in FROM clause

    当你的才华撑不起你的野心时,只有静下心学习才是唯一的出路

    '); +INSERT INTO `ape_document_article` VALUES (59, '

    在php7.0 linux环境中,在对foreach遍历时不能对正在遍历的数组进行删除元素,修改元素,增加元素操作,因为这些操作并不能对正在遍历的数组产生影响。

    场景还原

    \r\n$arr = [0, 1, 2, 3, 4];  // 一维数组,包含5个元素 \r\n\r\nforeach ($arr as $key => $value) {\r\n    if (0 === $key) {\r\n        unset($arr[3]);  // 删除第4个元素 \r\n    }\r\n    echo $key;\r\n}\r\n

    理论结果

    0124\r\n

    实际结果

    01234\r\n

    分析

    在我的常规理解中,unset可以删除数组中的指定元素,确实,unset是把数组$arr中的指定元素$arr[3]给删除了(不相信的话,可以把$arr数组打印出来看一看)。
    既然$arr[3]这个元素被删除,为什么在遍历的时候还会出现??
    我的猜想是:foreach在遍历的时候,会先把$arr数组拷贝一份,保证被遍历的数组 在遍历的过程中 数据的完整性,确保在遍历的时候不会被修改。所以我们使用unset去删除数组元素的时候,其实并不是删除正在被遍历的数组,而是在操作$arr变量。
    也就是说:被遍历的数组 !== $arr,被遍历的数组 === $arr的副本。

    当然这只是我的猜想...

    其他提示

    对正在被遍历的数组进行添加元素或者修改元素的操作跟删除元素的操作是一样的,不会对正在被遍历的数组产生影响。

    \r\n$arr = [0, 1, 2, 3, 4];  // 一维数组,包含5个元素 \r\n\r\nforeach ($arr as $key => $value) {\r\n    unset($arr[3]);\r\n    $arr[4] = 40;\r\n    $arr[10] = 100;\r\n    \r\n    echo $value;\r\n}\r\n

    结果依旧是一样:

    01234
    '); +INSERT INTO `ape_document_article` VALUES (60, '

    本地环境是和公司项目环境保持一致的 7.1,可是 laravel6.0 升级必须要求 7.2,(组内有小伙伴的本地环境是 7.2,然后 push 代码之后导致项目 dev 环境无法自动部署),想了想,还是得在本地弄一个方便切换 php 版本的东西。

    方法一:安装 php-version(如果没有用 valet,这个应该是可以的)

    step 1、使用 brew 安装多个 php 版本

    brew install php@7.1 // 原本有就不需要\r\nbrew install php@7.2

    step 2、发现 brew 安转 php-version 的命令失效了,那就手动安装吧

    [qian@bogon ~ ]$ mkdir $HOME/.local\r\n[qian@bogon ~ ]$ cd $HOME/.local\r\n[qian@bogon .local ]$ git clone https://github.com/wilmoore/php-version.git\r\n[qian@bogon .local ]$ source $HOME/.local/php-version/php-version.sh//测试  查看当前php版本\r\n[qian@bogon .local ]$ php-version* 7.1.18 7.2.22

    现在添加环境变量

    [qian@bogon ~ ]$ echo \"source $HOME/.local/php-version/php-version.sh\">> ~/.zshrc\r\n[qian@bogon ~ ]$ source ~/.zshrc

    切换 php 版本

    php-version 7.1

    php-version 7.2
    '); +INSERT INTO `ape_document_article` VALUES (61, '

    201909最新版XyPlayer 智能解析 X3.91 正式版 修复非m3u8资源无法选集的问题2019.9.17 更新 X3.91正式版


    下载地址

    '); +INSERT INTO `ape_document_article` VALUES (62, '
    $webApi =[
    \'api\' => \'https://list.youku.com/category/page?\', //请求列表 demo https://list.youku.com/category/page?c=97&type=show&p=1&s=6&u=2
    \'cate\' => [\'电影\'=>96,\'电视剧\'=>97,\'综艺\'=>85,\'少儿\'=>177,\'动漫\'=>100,\'纪录片\'=>84,\'音乐\'=>95],
    \'mode\' => [\'hot\' => 4, \'new\' => 5, \'all\' => 6, \'reviews\' => 2], //热门 最新 默认或者最新更新 好评
    \'status\'=> [\'finish\'=>1,\'update\'=>2], //更新状态
    \'getInfoApi\' => \'https://api.youku.com/videos/show.json?client_id=af43ee2709aa59ab&ext=show&video_id=\', //获取视频信息 demo https://api.youku.com/videos/show.json?client_id=af43ee2709aa59ab&ext=show&video_id=XNDQwODUyMzM0OA==
    \'listinfoApi\' => \'https://list.youku.com/show/module?callback=json&tab=showInfo\', //获取剧集列表 demo https://list.youku.com/show/module?id=308528&tab=showInfo&cname=电视剧&callback=json
    \'relistinfoApi\' => \'https://list.youku.com/show/episode?callback=json\', //获取剧集列表 demo https://list.youku.com/show/episode?id=308528&stage=reload_41&callback=json
    ];

    $videoId = \'5b5de27b671c417380c0\';
    $cate = \'电视剧\';
    var_dump(_get_video_list($webApi,$videoId,$cate)); die();

    function _get_video_list($webApi,$videoId,$cate){
    $getChildApi = $webApi[\'listinfoApi\'].\'&id=\'.$videoId.\'&cname=\'.$cate;
    $listInfo = file_get_contents($getChildApi);
    $listInfo = json_decode(winJsonToJson($listInfo), true);
    if (!is_array($listInfo) && empty($listInfo[\'html\'])) {
    return [];
    }
    $children = [];
    $list = _html_to_list($listInfo[\'html\']);
    $children = array_merge($children,$list[\'children_list\']);
    unset($listInfo);
    if (isset($list[\'album_tab_list\']) && !empty($list[\'album_tab_list\'])){
    foreach ($list[\'album_tab_list\'] as $album_tab){
    if (in_array($album_tab,$list[\'album_tab_list_finish\'])){
    continue;
    }
    $getChildApi = $webApi[\'relistinfoApi\'].\'&id=\'.$videoId.\'&stage=\'.$album_tab;
    $listInfo = file_get_contents($getChildApi);
    $listInfo = json_decode(winJsonToJson($listInfo), true);
    if (!is_array($listInfo) && empty($listInfo[\'html\'])) {
    continue;
    }
    $relist = _html_to_list($listInfo[\'html\'],true);
    $children = array_merge($children,$relist[\'children_list\']);
    unset($relist);
    }
    }
    return $children;
    }

    function _html_to_list($html,$reload=false){
    $result = [
    \'children_list\' =>[],
    \'album_tab_list_finish\' => []
    ];
    $hackEncoding = \'\';
    $dom = new DOMDocument();
    @$dom->loadHTML($hackEncoding .$html);//$a是上面得到的一些a标签
    $url = new DOMXPath($dom);
    if (!$reload){
    $result[\'album_tab_list\'] = [];
    $data = $url->evaluate(\'//ul[contains(@class, \"p-tab-pills\")]\');
    foreach ($data as $val) {
    $item = $val->childNodes;
    foreach ($item as $v) {
    $result[\'album_tab_list\'][] = trim($v->getAttribute(\'data-id\'));
    }
    }
    $data = $url->evaluate(\'//div[@class=\"p-panels\"]/div\');
    }else{
    $data = $url->evaluate(\'//div[@class=\"p-panel\"]\');
    }
    foreach ($data as $val) {
    $item = $val->childNodes;
    $album_tab_list_finish[] = trim($val->getAttribute(\'id\'));
    foreach ($item as $v) {
    foreach ($v->childNodes as $child){
    if ($child->getElementsByTagName(\'i\')->length >0){
    $icon_labels = $child->getElementsByTagName(\'i\')->item(0)->getAttribute(\'class\');
    }else{
    $icon_labels = \'\';
    }
    if (!empty($icon_labels)){
    $icon_labels = explode(\' \',$icon_labels);
    }
    $result[\'children_list\'][] = [
    \'title\' => $child->textContent,
    \'url\' => trimUrl(\'https:\'.$child->getElementsByTagName(\'a\')->item(0)->getAttribute(\'href\')),
    \'label_icon\' => $icon_labels
    ];
    }
    }
    }
    return $result;
    }

    function winJsonToJson($string){
    $string = substr($string,strpos($string,\'(\')+1);
    $string = substr($string,0,stripos($string,\')\'));
    return $string;
    }

    function trimUrl($url){
    $url = trimStr($url);
    $pattern=\"#(http|https)://(.*\\.)?.*\\..*#i\";
    if(!preg_match($pattern,$url)){
    return false;
    }
    $arr = parse_url($url);
    if (empty($arr)){
    return false;
    }
    if ($arr[\'scheme\'] !== \'https\' || !isset($arr[\'scheme\'])){
    $arr[\'scheme\'] = \'https\';
    }
    return $arr[\'scheme\'].\'://\'.$arr[\'host\'].$arr[\'path\'];
    }
    function trimStr($string){
    $string = strip_tags($string);
    return trim(str_replace(array(\"\'\",\'\"\',\" \",\"\\t\",\"\\n\",\"\\r\",\"\\r\\n\"), \"\", $string));
    }
    '); +INSERT INTO `ape_document_article` VALUES (63, '

    Redis批量删除key的小技巧,你知道吗?

    在使用redis的过程中,经常会遇到要批量删除某种规则的key,但是redis提供了批量查询一类key的命令keys或scan,没有提供批量删除某种规则key的命令,怎么办?看完本文即可,哈哈。

    一用keys+xargs实现

    开始实战

    1.连接redis,初始数据

    ./redis-cli -h 127.0.0.1 -p 6379
    127.0.0.1:6379> set java_suisui_1 1
    OK
    127.0.0.1:6379> set java_suisui_2 2
    OK
    127.0.0.1:6379> set java_suisui_3 3
    OK
    127.0.0.1:6379> set java_suisui_4 4
    OK

    2.使用keys命令查看数据

    127.0.0.1:6379> keys java_suisui_*
    1\"java_suisui_1\"
    2\"java_suisui_2\"
    3\"java_suisui_3\"
    4\"java_suisui_4\"

    3.退出redis的客户端

    127.0.0.1:6379exit

    4.使用keys+xargs批量删除

    [root@node1 src]# ./redis-cli -h 127.0.0.1 -p 6379 keys \"java_suisui*\" | xargs ./redis-cli -h 127.0.0.1 -p 6379 del
    (integer) 4

    执行上述命令后4条记录全部删除。

    5.注意事项

    redis是单线程架构,如果redis包含了大量的键,执行keys命令可能会造成redis阻塞,所以一般建议不要在生产环境下使用keys命令。如果非要遍历键删除的话,可以在以下三种情况使用:
    (1).在一个不对外提供服务的Redis从节点上执行,这样不会阻塞到客户端的请求,但是会影响到主从复制。
    (2).如果确认键值总数确实比较少,可以执行该命令。
    (3).使用scan命令渐进式的遍历所有键,可以有效防止阻塞。

    二、使用scan+xargs实现

    开始实战,前三个步骤和上面一样,不再重复记录。

    1.使用scan+xargs批量删除

    [root@node1 src]# ./redis-cli -h 127.0.0.1 -p 6379 --scan --pattern \'java*\' | xargs ./redis-cli -h 127.0.0.1 -p 6379 del
    (integer) 4

    执行上述命令后4条记录全部删除。

    三、xargs命令介绍

    xargs 可以将管道或标准输入(stdin)数据转换成命令行参数,也能够从文件的输出中读取数据。
    xargs 是一个强有力的命令,它能够捕获一个命令的输出,然后传递给另外一个命令。

    ./redis-cli -h 127.0.0.1 -p 6379 keys \"java_suisui*\" | xargs ./redis-cli -h 127.0.0.1 -p 6379 del

    上述命令解释:
    就是用keys java_suisui*查询出所有匹配的key,通过xargs命令,将前面查询出来的key作为后面redis的del命令的输入,这样就可以实现redis批量删除键了。

    '); +INSERT INTO `ape_document_article` VALUES (64, '

    Failed to decode response: zlib_decode(): data error

    \"微信图片_20191110224140.png\"

    解决问题的命令,composer diagnose  

     \"微信图片_20191110224308.png\"

     执行composer update 解决

    '); +INSERT INTO `ape_document_article` VALUES (65, '

    视频储存是很多人的一个难题…自己买个服务器又需要带宽有需要硬盘够大!

    看看怎么是一个完美的存储.

    开始操作

    原理 : 视频切片成 m3u8 之后,视频会变成一段段的 ts 格式的视频然后上传至图床


     $value) {\r\n	echo \"处理第\" . $value . \'个切片\' . \"\\n\";\r\n	$ali = upload(\'./\' . $v_path . \'player\' . $value . \'.ts\');\r\n	$m = str_replace(\'player\' . $value . \'.ts\', $ali, $m);\r\n	file_put_contents(\'./\' . $v_path . \'play.m3u8\', $m);\r\n}\r\n \r\necho \"处理完毕\" . \"\\n\";\r\necho \"播放链接为:/\" . $v_path . \'play.m3u8\';\r\n \r\nfunction upload($file) {\r\n	$post[\'file\'] = file_path($file);\r\n	$post[\'scene\'] = \'aeMessageCenterV2ImageRule\';\r\n	$post[\'name\'] = \'player.jpg\';\r\n	$rel = get_curl(\'https://kfupload.alibaba.com/mupload\', $post, \'iAliexpress/6.22.1 (iPhone; iOS 12.1.2; Scale/2.00)\');\r\n	$rel = json_decode($rel, true);\r\n \r\n	return $rel[\'url\'];\r\n}\r\n \r\nfunction get_curl($url, $post = 0, $ua = 0) {\r\n	$ch = curl_init();\r\n	curl_setopt($ch, CURLOPT_URL, $url);\r\n	// 不验证证书\r\n	curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);\r\n	curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);\r\n	// 最大执行时间\r\n	curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 120);\r\n	curl_setopt($ch, CURLOPT_TIMEOUT, 120);\r\n	$httpheader[] = \"Accept:application/json\";\r\n	$httpheader[] = \"Accept-Encoding:gzip,deflate,sdch\";\r\n	$httpheader[] = \"Accept-Language:zh-CN,zh;q=0.8\";\r\n	$httpheader[] = \"Connection:close\";\r\n	$ip = mt_rand(48, 140) . \".\" . mt_rand(10, 240) . \".\" . mt_rand(10, 240) . \".\" . mt_rand(10, 240); //随机 ip\r\n	$httpheader[] = \'CLIENT-IP:\' . $ip;\r\n	$httpheader[] = \'X-FORWARDED-FOR:\' . $ip;\r\n	curl_setopt($ch, CURLOPT_HTTPHEADER, $httpheader);\r\n	if ($post) {\r\n		curl_setopt($ch, CURLOPT_POST, 1);\r\n		curl_setopt($ch, CURLOPT_POSTFIELDS, $post);\r\n	}\r\n \r\n	if ($ua) {\r\n		curl_setopt($ch, CURLOPT_USERAGENT, $ua);\r\n	} else {\r\n		curl_setopt($ch, CURLOPT_USERAGENT, \"Mozilla/5.0 (Linux; U; Android 4.0.4; es-mx; HTC_One_X Build/IMM76D) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0\");\r\n	}\r\n	curl_setopt($ch, CURLOPT_ENCODING, \"gzip\");\r\n	curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);\r\n	$ret = curl_exec($ch);\r\n	curl_close($ch);\r\n	return $ret;\r\n}\r\nfunction mkFolder($path) {\r\n	if (!is_readable($path)) {\r\n		is_file($path) or mkdir($path, 0700);\r\n	}\r\n}\r\nfunction file_path($file) {\r\n	if (class_exists(\'CURLFile\')) {\r\n		return $post[\'file\'] = new \\CURLFile(realpath($file));\r\n	} else {\r\n		return $post[\'file\'] = \'@\' . realpath($file);\r\n	}\r\n}\r\n 

    把这个另存为 m3u8.php(什么名都成!这个就随便命名一下)

    运行命令:

    php m3u8.php 视频的储存路径 视频完整路径

    如:
    php m3u8.php mp4 wwwroot/test/test.mp4

    注意:这个接口只能上次小于 5MB 以下的图片(视频切片)所以切片完文件大小必须小于 5MB,还有就是 PHP 本身就不适合写脚本,单线程处理,很慢.建议用 PY 或者 java(我不会,希望有大佬写一下),其他的自己看代码就能懂,其实没啥.

    转载自 KIENG 博客

    '); +INSERT INTO `ape_document_article` VALUES (66, '

    找到需要下载的歌曲,然后分享,复制一下链接.

    这个随便找一个:

    1. //分享链接会泄露个人信息,我就*代替了
    2. https://node.kg.qq.com/play?s=**********&shareuid=********&topsource=a0_pn201001006_z11_u10923685_l0_t1577770997__

    右键查看源码:

    \"PHP-全民

    你会发现这其实一个 JSON 数据…那么就不用说了..

    源码

    1. php
    2.  
    3. header(\'content-type:application/json\');
    4.  
    5. $url = @$_GET[\'url\'];
    6.  
    7. if (empty($url)) {
    8. echo json_encode([\'code\' => 1, \'msg\' => \'没有播放链接\'], 320);
    9. exit;
    10. }
    11.  
    12. $data = curlGet($url);
    13.  
    14. $jsonData = getsubstr($data, \'window.__DATA__ = \', \';\');
    15.  
    16. $jsonArr = json_decode($jsonData, true);
    17.  
    18. $play = [
    19. \'avatar\' => $jsonArr[\'detail\'][\'avatar\'], //歌手头像
    20. \'content\' => $jsonArr[\'detail\'][\'content\'], //分享内容
    21. \'cover\' => $jsonArr[\'detail\'][\'cover\'], //歌曲封面
    22. \'nick\' => $jsonArr[\'detail\'][\'kg_nick\'], //歌手昵称
    23. \'playurl\' => $jsonArr[\'detail\'][\'playurl\'], //mp3 下载地址
    24. ];
    25.  
    26. echo json_encode($play, 320);
    27.  
    28. // 取中间文本函数
    29. function getsubstr($str, $leftStr, $rightStr) {
    30.  
    31. $left = strpos($str, $leftStr);
    32.  
    33. $right = strpos($str, $rightStr, $left);
    34.  
    35. if ($left < 0 or $right < $left) {
    36. return \'\';
    37. }
    38.  
    39. return substr($str, $left + strlen($leftStr), $right - $left - strlen($leftStr));
    40. }
    41. function curlGet($url) {
    42. $ch = curl_init();
    43. curl_setopt($ch, CURLOPT_URL, $url);
    44. curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    45. curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
    46. curl_setopt($ch,
    '); +INSERT INTO `ape_document_article` VALUES (67, '

    在这个充满敌意的互联网,我们对您的网站进行动态安全评估,若您精心部署的HTTPS符合最佳安全实践,我们将会为您的客户展示MySSL检测通过的安全签章和高评分的评级报告,提高客户对您网站的信任和支付信心,进而增加订单量,提升品牌价值。

    体验。

    \"给网站添加MySSL安全认证签章体验\"

     

    检测结果一:域名绑定未知非法IP

    对于这一类的攻击还是不得不防,万一被沦陷就损失惨重。回到正题,最后在MySSL通过在线用户反馈提交得以解决,解决的处理方式就是“不显示相关IP”。当然,现在已经没有显示问题,所以就没有办法提供截图。不管怎么样,问题得以解决,有可能是问题真实存在,也有可能是MySSL平台误判,都无从得知。对于网站的安全防御,后期还是不能松懈的。

    \"给网站添加MySSL安全认证签章体验\"

     

    检测结果二:PCI DSS不合规

    对于这个问题,其实就无关紧要了,这是一个浏览器兼容性的问题。解决的方法也很简单,对于WordPress网站来说,我们只需要通过SFTP找到yourdomain.com.conf文件中的TLS v1.0并删除即可。

    1. ssl_protocols                TLSv1.1 TLSv1.2 TLSv1.3;

    删除该标准后会导致老版本浏览器不兼容网站,但主流的Chrome、Firefox和国产浏览器基本都兼容。具体有关PCI DSS合规标准介绍和解决不合规问题,可以参阅详细原文《更严格的PCI DSS合规标准》。

    \"给网站添加MySSL安全认证签章体验\"

     

    添加MySSL安全认证签章

    给自己网站添加MySSL安全认证签章无非就是涂一个新鲜感,然后亲测尝试了一下。当今的互联网似乎都充满了敌意,网友对网站的安全和个人隐私信息都很担忧,如果有一个工具能够对网站进行动态安全评估,这会使用户对你的网站提高信任度。

    MySSL提供了4种样式添加安全认证签章,添加的方法也很简单,这里不再复述。详细的设置方法和样式代码可以阅读官方文档《为您的网站添加MySSL安全认证签章》,下面展示4种安全认证签章样式:

    \"给网站添加MySSL安全认证签章体验\"\"给网站添加MySSL安全认证签章体验\"\"给网站添加MySSL安全认证签章体验\"\"给网站添加MySSL安全认证签章体验\"

     

    有网友表示添加这样的HTTPS安全认证签章会给网站造成很多麻烦,比如:熊掌号收录问题、造成悬浮广告嫌疑。其中利弊各有取舍,出于好奇和安全体验了一次,大家可以在本页面底部查看效果。至于这个体验能持续多久,就不好保证了。毕竟这样的一个认证结构还没有被大众认可,所以大家自行取舍吧。

    '); +INSERT INTO `ape_document_article` VALUES (68, '

    代码


    **
    * Curl 伪造 IP 并从指定网址获取数据
    * @param $url string 接口地址
    * @param $ip string|boolean 伪造的 IP
    * @param $isMobile boolean 是否手机
    * @return bool|string 抓取到的内容
    */
    function apiCurl($url,$ip=false,$isMobile=false){
    $ch = curl_init(); // Curl 初始化
    $timeout = 30; // 超时时间:30s
    if($isMobile){
    $ua = \'Mozilla/5.0 (iPhone; CPU iPhone OS 12_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/72.0.3626.101 Mobile/15E148 Safari/605.1\';
    }else{
    $ua=\'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36\'; // 伪造抓取 UA
    }
    curl_setopt($ch, CURLOPT_URL, $url); // 设置 Curl 目标
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); // Curl 请求有返回的值
    curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout); // 设置抓取超时时间
    curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1); // 跟踪重定向
    curl_setopt($ch, CURLOPT_ENCODING, \"\"); // 设置编码
    curl_setopt($ch, CURLOPT_REFERER, $url); // 伪造来源网址
    if(!$ip){
    $ip = rand(0,254).\'.\'.rand(0,254).\'.\'.rand(0,254).\'.\'.rand(0,254);//随机生成ip数据
    }
    curl_setopt($ch, CURLOPT_USERAGENT, $ua); // 伪造ua
    curl_setopt($ch, CURLOPT_ENCODING, \'gzip\'); // 取消gzip压缩
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE); // https请求 不验证证书和hosts
    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
    $content = curl_exec($ch);
    curl_close($ch); // 结束 Curl
    return $content; // 函数返回内容
    }
    '); +INSERT INTO `ape_document_article` VALUES (69, '

    先在form 表达中添加 layedit

    <div class=\"layui-row layui-col-space10 layui-form-item\">
    <label class=\"layui-form-label\">问题内容:</label>
    <div class=\"layui-input-block\">
    <textarea id=\"container\" name=\"content\" lay-verify=\"content\"></textarea>
    </div>
    </div>

    初始化

    \r\nvar $ = layui.$
    ,layedit = layui.layedit
    ,form = layui.form;

    layedit.set({
    uploadImage: {
    url: \"{:url(\'/admin/words/upload\')}\" //接口url
    }
    });
    var index = layedit.build(\'container\'); //建立编辑器
    \r\n//处理同步问题
    form.verify({
    content: function(value) {
    return layedit.sync(index);
    }
    });


    处理办法解析

    在<textarea>标签中加入lay-verify=\"content\" 然后在form的表单自定义验证中加入如下代码即可

    form.verify({
    content: function(value) {
    return layedit.sync(index);
    }
    });


    或者提交时候使用

    form.on(\'submit(form)\', function(data){  \r\n  layedit.sync(index);\r\n  //获取数据用 $(selector).serialize() 而不是data.field,data.field获取会是修改后的值,或者延时一秒也可以\r\n})
    '); +INSERT INTO `ape_document_article` VALUES (70, '

    # Git

    # 常用命令

    常用

    git clone 克隆

    git pull 拉取

    git add . 加入缓存区

    git commit -m “” 提交到本地

    git push origin xxx 推送到远程服务器

    git merge xxx 合并 合并其他分支代码到当前分支(当前分支获取到代码后,是commit本地,需要push才会到远程分支)

    git checkout xxx 切换

    git pull origin xxx 拉取其他分支代码到当前分支(当前分支获取到代码后,是commit本地,需要push才会到远程分支)

    git branch 查看分支

    git branch -a 查看全部分支

    git remote update origin --prune 更新远程分支

    git branch xxx 创建一个分支

    git branch -d xxx 删除分支

     

    打tag

    git tag 查看tag列表

    git show v1.0 查看tag信息

    git tag -a v1.0.0 -m \'tag备注\' 打一个tag

    git push origin v1.0.0 将打好的tag推到远程仓库

     

    暂存(add后就表示修改的文件新增的文件添加到了缓存区stage)

    git status 查看当前状态

     

    撤销(可以撤销add暂存到缓存区的文件)

    git reset HEAD 撤销上一次add

    git reset HEAD xxx.xxx 撤销某一个文件的add

     

    回滚(可以回滚commit,如果想回滚远程分支,先回滚当前分支,然后push)

    git reset --hard HEAD^ 回滚上个版本(^的个数就是回滚几个版本,也可以用HEAD~2)

    git reset --hard xxxx 回滚到某个版本号

    git push origin xxx -f (回滚本地分支后如何回滚远程分支,需要强制推到远程分支,这样远程分支也会被回滚,强推容易回滚掉别人的版本)

    git log 查看历史提交(版本号)

    git reflow 操作历史

     

    初始化

    git init 初始化

    git remote add origin “xxx” 关联远程仓库地址

    git config user.name  “xxx” 设置名字

    git config user.email “xxx” 设置邮箱

     

    GitHub

    先fork一个仓库,然后pull request贡献代码

    # 工作场景

    develop:多人开发的线上分支

    new_branch:自己的本地分支(保持与develop同步)



    拉取某个项目仓库

    git clone xxx@xxx.git

     

    创建自己的分支,切换到该分支

    git branch new_branch

    git checkout new_branch

    写代码 xxx xxx

    提交代码

    git pull origin develop // 同步线上分支develop到本地new_branch分支

    // 合并代码/解决冲突

    git add . 或者 git add xxx.xx // 添加到缓存区

    git commit -m \"完成xxx,修复xxx,解决xxx,恢复xxx\" // 提交到本地

    git push origin new_branch // 推送到远程new_branch分支

    git checkout develop // 切换到多人开发的develop分支上

    git pull origin develop // 拉一下最新代码

    git merge new_branch // 将自己分支的代码合并到develop分支上

    git push origin develop // 推送到远程develop分支

    git checkout new_branch // 切换回自己的分支

    '); +INSERT INTO `ape_document_article` VALUES (71, '

    Redis支持RDB和AOF两种持久化机制,持久化功能有效地避免因进程退出造成的数据丢失问题,当下次重启时利用之前持久化的文件即可实现数 据恢复。理解掌握持久化机制对于Redis运维非常重要

    1.RDB持久化

    RDB持久化是把当前进程数据生成快照保存到硬盘的过程,触发RDB持久化过程分为手动触发和自动触发

    1)触发机制

    手动触发分别对应save和bgsave命令

    ·save命令:阻塞当前Redis服务器,直到RDB过程完成为止,对于内存 比较大的实例会造成长时间阻塞,线上环境不建议使用

    ·bgsave命令:Redis进程执行fork操作创建子进程,RDB持久化过程由子 进程负责,完成后自动结束。阻塞只发生在fork阶段,一般时间很短

    2)自动触发RDB的持久

    1)使用save相关配置,如“save m n”。表示m秒内数据集存在n次修改 时,自动触发bgsave。

    2)如果从节点执行全量复制操作,主节点自动执行bgsave生成RDB文件并发送给从节点,更多细节见6.3节介绍的复制原理。

    3)执行debug reload命令重新加载Redis时,也会自动触发save操作。

    4)默认情况下执行shutdown命令时,如果没有开启AOF持久化功能则 自动执行bgsave。

    bgsave是主流的触发RDB持久化方式

    1)执行bgsave命令,Redis父进程判断当前是否存在正在执行的子进 程,如RDB/AOF子进程,如果存在bgsave命令直接返回。

    2)父进程执行fork操作创建子进程,fork操作过程中父进程会阻塞,通 过info stats命令查看latest_fork_usec选项,可以获取最近一个fork操作的耗时,单位为微秒

    3)父进程fork完成后,bgsave命令返回“Background saving started”信息并不再阻塞父进程,可以继续响应其他命令。

    4)子进程创建RDB文件,根据父进程内存生成临时快照文件,完成后 对原有文件进行原子替换。执行lastsave命令可以获取最后一次生成RDB的 时间,对应info统计的rdb_last_save_time选项。

    5)进程发送信号给父进程表示完成,父进程更新统计信息,具体见 info Persistence下的rdb_*相关选项。

    RDB文件的处理

    保存:RDB文件保存在dir配置指定的目录下,文件名通过dbfilename配 置指定。可以通过执行config set dir{newDir}和config set dbfilename{newFileName}运行期动态执行,当下次运行时RDB文件会保存到新目录。

    RDB的优缺点

    RDB的优点:

    ·RDB是一个紧凑压缩的二进制文件,代表Redis在某个时间点上的数据 快照。非常适用于备份,全量复制等场景。比如每6小时执行bgsave备份, 并把RDB文件拷贝到远程机器或者文件系统中(如hdfs),用于灾难恢复。

    ·Redis加载RDB恢复数据远远快于AOF的方式。

    RDB的缺点:

    ·RDB方式数据没办法做到实时持久化/秒级持久化。因为bgsave每次运 行都要执行fork操作创建子进程,属于重量级操作,频繁执行成本过高。

    ·RDB文件使用特定二进制格式保存,Redis版本演进过程中有多个格式 的RDB版本,存在老版本Redis服务无法兼容新版RDB格式的问题。

    针对RDB不适合实时持久化的问题,Redis提供了AOF持久化方式来解决。

    2.AOF持久化

    AOF(append only file)持久化:以独立日志的方式记录每次写命令, 重启时再重新执行AOF文件中的命令达到恢复数据的目的。AOF的主要作用 是解决了数据持久化的实时性,目前已经是Redis持久化的主流方式

    1)使用AOF

    开启AOF功能需要设置配置:appendonly yes,默认不开启。AOF文件名 通过appendfilename配置设置,默认文件名是appendonly.aof。保存路径同 RDB持久化方式一致,通过dir配置指定。AOF的工作流程操作:命令写入 (append)、文件同步(sync)、文件重写(rewrite)、重启加载 (load)

    1)所有的写入命令会追加到aof_buf(缓冲区)中。

    2)AOF缓冲区根据对应的策略向硬盘做同步操作。

    AOF为什么把命令追加到aof_buf中?Redis使用单线程响应命令,如 果每次写AOF文件命令都直接追加到硬盘,那么性能完全取决于当前硬盘负 载。先写入缓冲区aof_buf中,还有另一个好处,Redis可以提供多种缓冲区同步硬盘的策略,在性能和安全性方面做出平衡

    3)随着AOF文件越来越大,需要定期对AOF文件进行重写,达到压缩的目的。

    重写后的AOF文件为什么可以变小?有如下原因:

    1)进程内已经超时的数据不再写入文件。

    2)旧的AOF文件含有无效命令,如del key1、hdel key2、srem keys、set a111、set a222等。重写使用进程内数据直接生成,这样新的AOF文件只保

    留最终数据的写入命令。

    3)多条写命令可以合并为一个,如:lpush list a、lpush list b、lpush list c可以转化为:lpush list a b c。为了防止单条命令过大造成客户端缓冲区溢 出,对于list、set、hash、zset等类型操作,以64个元素为界拆分为多条。

    AOF重写降低了文件占用空间,除此之外,另一个目的是:更小的AOF 文件可以更快地被Redis加载

    AOF重写过程可以手动触发和自动触发:

    ·手动触发:直接调用bgrewriteaof命令。

    ·自动触发:根据auto-aof-rewrite-min-size和auto-aof-rewrite-percentage参数确定自动触发时机

    ·auto-aof-rewrite-min-size:表示运行AOF重写时文件最小体积,默认 为64MB。

    ·auto-aof-rewrite-percentage:代表当前AOF文件空间 (aof_current_size)和上一次重写后AOF文件空间(aof_base_size)的比值。

    自动触发时机=aof_current_size>auto-aof-rewrite-minsize&&(aof_current_size-aof_base_size)/aof_base_size>=auto-aof-rewritepercentage

    其中aof_current_size和aof_base_size可以在info Persistence统计信息中查看。


    4)当Redis服务器重启时,可以加载AOF文件进行数据恢复。

    流程说明:

    1)AOF持久化开启且存在AOF文件时,优先加载AOF文件,打印如下日志:

    * DB loaded from append only file: 5.841 seconds

    2)AOF关闭或者AOF文件不存在时,加载RDB文件,打印如下日志:

    * DB loaded from disk: 5.586 seconds

    3)加载AOF/RDB文件成功后,Redis启动成功。

    4)AOF/RDB文件存在错误时,Redis启动失败并打印错误信息。

    本章重点回顾

    1)Redis提供了两种持久化方式:RDB和AOF。

    2)RDB使用一次性生成内存快照的方式,产生的文件紧凑压缩比更 高,因此读取RDB恢复速度更快。由于每次生成RDB开销较大,无法做到实

    时持久化,一般用于数据冷备和复制传输。

    3)save命令会阻塞主线程不建议使用,bgsave命令通过fork操作创建子 进程生成RDB避免阻塞。

    4)AOF通过追加写命令到文件实现持久化,通过appendfsync参数可以 控制实时/秒级持久化。因为需要不断追加写命令,所以AOF文件体积逐渐变大,需要定期执行重写操作来降低文件体积。

    5)AOF重写可以通过auto-aof-rewrite-min-size和auto-aof-rewritepercentage参数控制自动触发,也可以使用bgrewriteaof命令手动触发。

    6)子进程执行期间使用copy-on-write机制与父进程共享内存,避免内 存消耗翻倍。AOF重写期间还需要维护重写缓冲区,保存新的写入命令避免数据丢失。

    7)持久化阻塞主线程场景有:fork阻塞和AOF追加阻塞。fork阻塞时间 跟内存量和系统有关,AOF追加阻塞说明硬盘资源紧张。

    8)单机下部署多个实例时,为了防止出现多个子进程执行重写操作, 建议做隔离控制,避免CPU和IO资源竞争。

    作者:huxt

    链接:https://www.jianshu.com/p/d3ba7b8ad964

    来源:简书

    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

    '); +INSERT INTO `ape_document_article` VALUES (72, '

    企业业务量比较小的时候,单台服务器就可以满足业务需要了。但是随着业务发展,单服务器的问题就凸显出来了:

    负载均衡器可以解决以上问题

    1 负载均衡器拓扑图

    \"loadbalancer\"

    本文会根据拓扑图,用haproxy和keepalived搭建一个负载均衡器

    2 准备

    2.1 准备环境

    准备5台CentOS7.3主机和一个VIP地址:

    2.2 主机配置

    2.2.1 所有主机上关闭防火墙

    systemctl stop firewalld\r\nsystemctl disable firewalld

    2.2.2 所有主机关闭selinux

    setenforce 0\r\nvi /etc/selinux/config\r\nSELINUX=disabled

    2.3 安装haproxy和keepalived

    lb1和lb2上安装haproxy和keepalived

    yum install haproxy keepalived -y

    2.4 安装nginx(有其他后端测程序,可省略此步)

    s1 s2 s3上安装nginx,目的是把nginx作为后端,如果有其他后端程序,这一步可以省略

    yum install epel-release -y\r\nyum install nginx -y

    2.3 配置keepalived

    KeepAlived是基于VRRP(Virtual Router Redundancy Protocol,虚拟路由冗余协议)实现的一个高可用方案,通过VIP(虚拟IP)和心跳检测来实现高可用

    Keepalived有两个角色,Master和Backup。一般会是1个Master,多个Backup。

    Master会绑定VIP到自己网卡上,对外提供服务。Master和Backup会定时确定对方状态,当Master不可用的时候,Backup会通知网关,并把VIP绑定到自己的网卡上,实现服务不中断,高可用

    2.3.1 配置Master

    编辑lb1(192.168.1.101)上的/etc/keepalived/keepalived.conf

    ! Configuration File for keepalived\r\n\r\nglobal_defs {\r\n   # 通知邮件服务器的配置\r\n   notification_email {\r\n     # 当master失去VIP或则VIP的时候,会发一封通知邮件到your-email@qq.com\r\n     your-email@qq.com\r\n   }\r\n   # 发件人信息\r\n   notification_email_from keepalived@qq.com\r\n   # 邮件服务器地址\r\n   smtp_server 127.0.0.1\r\n   # 邮件服务器超时时间\r\n   smtp_connect_timeout 30\r\n   # 邮件TITLE\r\n   router_id LVS_DEVEL\r\n}\r\n\r\nvrrp_instance VI_1 {\r\n    # 主机: MASTER\r\n    # 备机: BACKUP\r\n    state MASTER\r\n    # 实例绑定的网卡, 用ip a命令查看网卡编号\r\n    interface eno16777984\r\n    # 虚拟路由标识,这个标识是一个数字(1-255),在一个VRRP实例中主备服务器ID必须一样\r\n    virtual_router_id 88\r\n    # 优先级,数字越大优先级越高,在一个实例中主服务器优先级要高于备服务器\r\n    priority 100\r\n    # 主备之间同步检查的时间间隔单位秒\r\n    advert_int 1\r\n    # 验证类型和密码\r\n    authentication {\r\n        # 验证类型有两种 PASS和HA\r\n        auth_type PASS\r\n        # 验证密码,在一个实例中主备密码保持一样\r\n        auth_pass 11111111\r\n    }\r\n    # 虚拟IP地址,可以有多个,每行一个\r\n    virtual_ipaddress {\r\n        192.168.1.100\r\n    }\r\n}\r\n\r\nvirtual_server 192.168.1.100 443 {\r\n    # 健康检查时间间隔\r\n    delay_loop 6\r\n    # 调度算法\r\n    # Doc: http://www.keepalived.org/doc/scheduling_algorithms.html\r\n    # Round Robin (rr)\r\n    # Weighted Round Robin (wrr)\r\n    # Least Connection (lc)\r\n    # Weighted Least Connection (wlc)\r\n    # Locality-Based Least Connection (lblc)\r\n    # Locality-Based Least Connection with Replication (lblcr)\r\n    # Destination Hashing (dh)\r\n    # Source Hashing (sh)\r\n    # Shortest Expected Delay (seq)\r\n    # Never Queue (nq)\r\n    # Overflow-Connection (ovf)\r\n    lb_algo rr\r\n    lb_kind NAT\r\n    persistence_timeout 50\r\n    protocol TCP\r\n    # 通过调度算法把Master切换到真实的负载均衡服务器上\r\n    # 真实的主机会定期确定进行健康检查,如果MASTER不可用,则切换到备机上\r\n    real_server 192.168.1.101 443 {\r\n        weight 1\r\n        TCP_CHECK {\r\n            # 连接超端口\r\n            connect_port 443\r\n            # 连接超时时间\r\n            connect_timeout 3\r\n        }\r\n    }\r\n    real_server 192.168.1.102 443 {\r\n        weight 1\r\n        TCP_CHECK {\r\n            connect_port 443\r\n            connect_timeout 3\r\n        }\r\n    }\r\n}

    2.3.2 配置BACKUP

    编辑lb2(192.168.1.102)上的/etc/keepalived/keepalived.conf

    ! Configuration File for keepalived\r\n\r\nglobal_defs {\r\n   # 通知邮件服务器的配置\r\n   notification_email {\r\n     # 当master失去VIP或则VIP的时候,会发一封通知邮件到your-email@qq.com\r\n     your-email@qq.com\r\n   }\r\n   # 发件人信息\r\n   notification_email_from keepalived@qq.com\r\n   # 邮件服务器地址\r\n   smtp_server 127.0.0.1\r\n   # 邮件服务器超时时间\r\n   smtp_connect_timeout 30\r\n   # 邮件TITLE\r\n   router_id LVS_DEVEL\r\n}\r\n\r\nvrrp_instance VI_1 {\r\n    # 主机: MASTER\r\n    # 备机: BACKUP\r\n    state BACKUP\r\n    # 实例绑定的网卡, 用ip a命令查看网卡编号\r\n    interface eno16777984\r\n    # 虚拟路由标识,这个标识是一个数字(1-255),在一个VRRP实例中主备服务器ID必须一样\r\n    virtual_router_id 88\r\n    # 优先级,数字越大优先级越高,在一个实例中主服务器优先级要高于备服务器\r\n    priority 99\r\n    # 主备之间同步检查的时间间隔单位秒\r\n    advert_int 1\r\n    # 验证类型和密码\r\n    authentication {\r\n        # 验证类型有两种 PASS和HA\r\n        auth_type PASS\r\n        # 验证密码,在一个实例中主备密码保持一样\r\n        auth_pass 11111111\r\n    }\r\n    # 虚拟IP地址,可以有多个,每行一个\r\n    virtual_ipaddress {\r\n        192.168.1.100\r\n    }\r\n}\r\n\r\nvirtual_server 192.168.1.100 443 {\r\n    # 健康检查时间间隔\r\n    delay_loop 6\r\n    # 调度算法\r\n    # Doc: http://www.keepalived.org/doc/scheduling_algorithms.html\r\n    # Round Robin (rr)\r\n    # Weighted Round Robin (wrr)\r\n    # Least Connection (lc)\r\n    # Weighted Least Connection (wlc)\r\n    # Locality-Based Least Connection (lblc)\r\n    # Locality-Based Least Connection with Replication (lblcr)\r\n    # Destination Hashing (dh)\r\n    # Source Hashing (sh)\r\n    # Shortest Expected Delay (seq)\r\n    # Never Queue (nq)\r\n    # Overflow-Connection (ovf)\r\n    lb_algo rr\r\n    lb_kind NAT\r\n    persistence_timeout 50\r\n    protocol TCP\r\n    # 通过调度算法把Master切换到真实的负载均衡服务器上\r\n    # 真实的主机会定期确定进行健康检查,如果MASTER不可用,则切换到备机上\r\n    real_server 192.168.1.101 443 {\r\n        weight 1\r\n        TCP_CHECK {\r\n            # 连接超端口\r\n            connect_port 443\r\n            # 连接超时时间\r\n            connect_timeout 3\r\n        }\r\n    }\r\n    real_server 192.168.1.102 443 {\r\n        weight 1\r\n        TCP_CHECK {\r\n            connect_port 443\r\n            connect_timeout 3\r\n        }\r\n    }\r\n}

    2.4 配置haproxy

    编辑lb1(192.168.1.101)和lb2(192.168.1.102)上的/etc/haproxy/haproxy.cfg
    把后端服务器IP(192.168.1.2, 192.168.1.3, 192.168.1.4)加到backend里

    #---------------------------------------------------------------------\r\n# Global settings\r\n#---------------------------------------------------------------------\r\nglobal\r\n    log         127.0.0.1 local2\r\n\r\n    chroot      /var/lib/haproxy\r\n    pidfile     /var/run/haproxy.pid\r\n    maxconn     4096\r\n    user        haproxy\r\n    group       haproxy\r\n    daemon\r\n\r\n    # turn on stats unix socket\r\n    stats socket /var/lib/haproxy/stats\r\n\r\nlisten stats\r\n    bind    *:9000\r\n    mode    http\r\n    stats   enable\r\n    stats   hide-version\r\n    stats   uri       /stats\r\n    stats   refresh   30s\r\n    stats   realm     Haproxy\\ Statistics\r\n    stats   auth      admin:admin\r\n\r\n\r\nfrontend  k8s-api\r\n    bind *:443\r\n    mode tcp\r\n    option tcplog\r\n    tcp-request inspect-delay 5s\r\n    tcp-request content accept if { req_ssl_hello_type 1 }\r\n    default_backend k8s-api-backend\r\n\r\nbackend k8s-api-backend\r\n    mode tcp\r\n    option tcplog\r\n    option tcp-check\r\n    balance roundrobin\r\n    server master1 192.167.1.2:80 maxconn 1024 weight 5 check\r\n    server master2 192.167.1.3:80 maxconn 1024 weight 5 check\r\n    server master3 192.167.1.4:80 maxconn 1024 weight 5 check

    2.5 配置nginx

    给nginx添加SSL证书,配置过程略

    vi /usr/share/nginx/html/index.html

    把index.html里面字符串Welcome to nginx改成Welcome to nginx HA

    3 启动服务

    3.1 启动nginx

    sudo systemctl start nginx\r\nsudo systemctl enable nginx

    3.2 启动haproxy

    sudo systemctl start haproxy\r\nsudo systemctl enable haproxy

    3.3 启动keepalived

    sudo systemctl start keepalived\r\nsudo systemctl enable keepalived

    在MASTER上运行ip a

     eno16777984: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP qlen 1000\r\n    link/ether 00:xx:xx:xx:3d:0c brd ff:ff:ff:ff:ff:ff\r\n    inet 192.168.1.101/24 brd 192.168.1.255 scope global eno16777984\r\n       valid_lft forever preferred_lft forever\r\n    inet 192.168.1.100/32 scope global eno16777984\r\n       valid_lft forever preferred_lft forever\r\n    inet6 eeee:eeee:1c9d:2009:250:56ff:fe9c:3d0c/64 scope global noprefixroute dynamic\r\n       valid_lft 7171sec preferred_lft 7171sec\r\n    inet6 eeee::250:56ff:eeee:3d0c/64 scope link\r\n       valid_lft forever preferred_lft forever

    会发现VIP(192.168.1.100)已经绑定好了

    inet 192.168.1.100/32 scope global eno16777984\r\n       valid_lft forever preferred_lft forever

    如果发现VIP无法绑定

    vi /etc/sysctl.conf

    添加两行

    net.ipv4.ip_forward = 1\r\nnet.ipv4.ip_nonlocal_bind = 1

    让新配置生效

    sysctl -p

    4 验证

    4.1 查看状态

    1. 在浏览器输入 http://192.168.1.100:9000/stats 查看haproxy状态\r\n2. 在浏览器输入 https://192.168.1.100 查看服务状态\r\n   是否成功显示为nginx欢迎页面

    4.2 主备切换

    1. 在浏览器输入 https://192.168.1.100 查看是否成功显示nginx欢迎页面\r\n2. lb1(192.168.1.101)关机,查看是否还可以访问https://192.168.1.100, 如果成功,则说明VIP成功切换到备机\r\n3. 在lb2(192.168.1.102)上执行ip a,查看网卡是否绑定VIP(192.168.1.100)\r\n3. 启动lb1(192.168.1.101)\r\n   目的是为了验证VIP是否切回MASTER主机(因为MASTER端的配置文件中priority为100,而BACKUP为99,health check会自动把VIP绑定到priority高的主机上)

    转载自 https://yq.aliyun.com/articles/609851?spm=a2c4e.11153940.bloghomeflow.104.417a291abDIzgA

    '); +INSERT INTO `ape_document_article` VALUES (73, '

    说明:仅以最快的速度记录部署成功,故会少很多步骤和介绍

    准备

    虚拟机(CentOS 7)

    准备了4台虚拟机,用于测试

    IP 作用

    192.168.1.128
    keepalived master
    192.168.1.129
     keepalived backup
    192.168.1.130
    nginx1
    192.168.1.131
    nginx2
    192.168.1.200
    虚拟ip VIP

    架构示意图


    软件安装

    在192.168.1.128及192.168.1.129上安装keepalived

    在192.168.1.130及192.168.1.131上安装nginx

    防火墙配置

    所有主机上关闭防火墙,仅部署测试用,具体配置请自行参考

    systemctl stop firewalld\r\nsystemctl disable firewalld


    基础软件安装

    yum install gcc\r\nyum -y install openssl-devel\r\nyum -y install libnl libnl-devel\r\nyum install -y libnfnetlink-devel\r\nyum -y install net-tools\r\nyum install vim -y

    在两台keepalived服务器安装 KeepAlived 和LVS管理工具 ipvsadm安装

    yum install  keepalived  ipvsadm -y

    keepalived启动等命令

    systemctl  start|stop|restart|status|enable  keepalived

    设置自启

    systemctl enable keepalived

    配置MASTER

    进入192.168.1.128服务器

    cd /etc/keepalived

    #备份默认的keepalived配置

    mv keepalived.conf keepalived-back.conf\r\nvim keepalived.conf

    添加以下配置:

    global_defs {\r\n   notification_email {\r\n         edisonchou@hotmail.com\r\n   }\r\n   notification_email_from sns-lvs@gmail.com\r\n   smtp_server 192.168.80.1\r\n   smtp_connection_timeout 30\r\n   router_id LVS_DEVEL  # 设置lvs的id,在一个网络内应该是唯一的\r\n}\r\nvrrp_instance VI_1 {\r\n    state MASTER   #指定Keepalived的角色,MASTER为主,BACKUP为备 记得大写\r\n    interface eno16777736  #网卡id 不同的电脑网卡id会有区别 可以使用:ip a查看\r\n    virtual_router_id 51  #虚拟路由编号,主备要一致\r\n    priority 100  #定义优先级,数字越大,优先级越高,主DR必须大于备用DR\r\n    advert_int 1  #检查间隔,默认为1s\r\n    authentication {   #这里配置的密码最多为8位,主备要一致,否则无法正常通讯\r\n        auth_type PASS\r\n        auth_pass 1111\r\n    }\r\n    virtual_ipaddress {\r\n        192.168.1.200  #定义虚拟IP(VIP)为192.168.1.200,可多设,每行一个\r\n    }\r\n}\r\n# 定义对外提供服务的LVS的VIP以及port\r\nvirtual_server 192.168.1.200 80 {\r\n    delay_loop 6 # 设置健康检查时间,单位是秒\r\n    lb_algo rr # 设置负载调度的算法为wlc\r\n    lb_kind DR # 设置LVS实现负载的机制,有NAT、TUN、DR三个模式\r\n    nat_mask 255.255.255.0\r\n    persistence_timeout 0\r\n    protocol TCP\r\n    real_server 192.168.1.130 80 {  # 指定real server1的IP地址\r\n        weight 3   # 配置节点权值,数字越大权重越高\r\n        TCP_CHECK {\r\n        connect_timeout 10\r\n        nb_get_retry 3\r\n        delay_before_retry 3\r\n        connect_port 80\r\n        }\r\n    }\r\n    real_server 192.168.1.131 80 {  # 指定real server2的IP地址\r\n        weight 3  # 配置节点权值,数字越大权重越高\r\n        TCP_CHECK {\r\n        connect_timeout 10\r\n        nb_get_retry 3\r\n        delay_before_retry 3\r\n        connect_port 80\r\n        }\r\n     }\r\n}

    配置BACKUP

    进入192.168.1.129服务器

    cd /etc/keepalived

    #备份默认的keepalived配置

    mv keepalived.conf keepalived-back.conf\r\nvim keepalived.conf

    添加以下配置:

    global_defs {\r\n   notification_email {\r\n         edisonchou@hotmail.com\r\n   }\r\n   notification_email_from sns-lvs@gmail.com\r\n   smtp_server 192.168.80.1\r\n   smtp_connection_timeout 30\r\n   router_id LVS_DEVEL  # 设置lvs的id,在一个网络内应该是唯一的\r\n}\r\nvrrp_instance VI_1 {\r\n    state BACKUP #指定Keepalived的角色,MASTER为主,BACKUP为备 记得大写\r\n    interface eno16777736  #网卡id 不同的电脑网卡id会有区别 可以使用:ip a查看\r\n    virtual_router_id 51  #虚拟路由编号,主备要一致\r\n    priority 50  #定义优先级,数字越大,优先级越高,主DR必须大于备用DR\r\n    advert_int 1  #检查间隔,默认为1s\r\n    authentication {   #这里配置的密码最多为8位,主备要一致,否则无法正常通讯\r\n        auth_type PASS\r\n        auth_pass 1111\r\n    }\r\n    virtual_ipaddress {\r\n        192.168.1.200  #定义虚拟IP(VIP)为192.168.1.200,可多设,每行一个\r\n    }\r\n}\r\n# 定义对外提供服务的LVS的VIP以及port\r\nvirtual_server 192.168.1.200 80 {\r\n    delay_loop 6 # 设置健康检查时间,单位是秒\r\n    lb_algo rr # 设置负载调度的算法为wlc\r\n    lb_kind DR # 设置LVS实现负载的机制,有NAT、TUN、DR三个模式\r\n    nat_mask 255.255.255.0\r\n    persistence_timeout 0\r\n    protocol TCP\r\n    real_server 192.168.1.130 80 {  # 指定real server1的IP地址\r\n        weight 3   # 配置节点权值,数字越大权重越高\r\n        TCP_CHECK {\r\n        connect_timeout 10\r\n        nb_get_retry 3\r\n        delay_before_retry 3\r\n        connect_port 80\r\n        }\r\n    }\r\n    real_server 192.168.1.131 80 {  # 指定real server2的IP地址\r\n        weight 3  # 配置节点权值,数字越大权重越高\r\n        TCP_CHECK {\r\n        connect_timeout 10\r\n        nb_get_retry 3\r\n        delay_before_retry 3\r\n        connect_port 80\r\n        }\r\n     }\r\n}\r\n

    配置注意项

    router_id

    后面跟的自定义的ID在同一个网络下是一致的

    state

    state后跟的MASTER和BACKUP必须是大写;否则会造成配置无法生效的问题

    interface

    网卡ID;这个值不能完全拷贝我的配置,要根据自己的实际情况来看,可以使用以下方式查询

    ip a


    priority

    主备优先级

    MASTER中配置的priority必须比BACKUP大;差值最好>=50

    authentication

    主备之间的认证方式

    一般使用PASS即可;主备的配置必须一致;否则无法通讯,会导致裂脑;密码不能大于8位

    virtual_ipaddress

    配置的VIP;允许配置多个

    启动keepalived

    在192.168.1.128和192.168.1.129下分别执行以下指令重启keepalived

    systemctl start keepalived

    检查主keepalived 启动后的配置情况

    ip a


    如果网卡下出现192.168.1.200(VIP)说明主已经启动成功

    检查备keepalived 启动后的配置情况

    ip a

    备服务器的网卡下没有出现192.168.1.200(VIP)的ip,说明备服务正常

    注:如果这里也出现了VIP,那么说明裂脑了,需要检查防火墙是否配置正确;是否允许了vrrp的多播通讯


    nginx安装

    只需要在192.168.1.130及192.168.1.131上安装nginx即可

    安装nginx,目的是把nginx作为后端,如果有其他后端程序,这一步可以省略

    yum install epel-release -y\r\nyum install nginx -y

    启动nginx服务

    确保nginx已经正常运行了

    ps -ef|grep nginx

    编辑realserver脚本文件两台机器都要搞

    进入init文件夹

    cd /etc/init.d/

    编辑脚本

    vim realserver

    添加以下脚本

    #虚拟的vip 根据自己的实际情况定义

    #!/bin/bash\r\n#虚拟的vip 根据自己的实际情况定义\r\nSNS_VIP=192.168.1.200\r\n/etc/rc.d/init.d/functions\r\ncase \"$1\" in\r\nstart)\r\n       ifconfig lo:0 $SNS_VIP netmask 255.255.255.255 broadcast $SNS_VIP\r\n       /sbin/route add -host $SNS_VIP dev lo:0\r\n       echo \"1\" >/proc/sys/net/ipv4/conf/lo/arp_ignore\r\n       echo \"2\" >/proc/sys/net/ipv4/conf/lo/arp_announce\r\n       echo \"1\" >/proc/sys/net/ipv4/conf/all/arp_ignore\r\n       echo \"2\" >/proc/sys/net/ipv4/conf/all/arp_announce\r\n       sysctl -p >/dev/null 2>&1\r\n       echo \"RealServer Start OK\"\r\n       ;;\r\nstop)\r\n       ifconfig lo:0 down\r\n       route del $SNS_VIP >/dev/null 2>&1\r\n       echo \"0\" >/proc/sys/net/ipv4/conf/lo/arp_ignore\r\n       echo \"0\" >/proc/sys/net/ipv4/conf/lo/arp_announce\r\n       echo \"0\" >/proc/sys/net/ipv4/conf/all/arp_ignore\r\n       echo \"0\" >/proc/sys/net/ipv4/conf/all/arp_announce\r\n       echo \"RealServer Stoped\"\r\n       ;;\r\n*)\r\n       echo \"Usage: $0 {start|stop}\"\r\n       exit 1\r\nesac\r\nexit 0\r\n

    保存并设置脚本的执行权限

    chmod 755 /etc/init.d/realserver

    因为realserver脚本中用到了/etc/rc.d/init.d/functions,所以一并设置权限

    chmod 755 /etc/rc.d/init.d/functions

    执行脚本

    service realserver start


    查看执行结果

    ip a

    如果看到以下效果,说明脚本已经执行成功了



    LVS管理工具-ipvsadm

    查看统计

    查看当前配置的虚拟服务和各个RS的权重

     ipvsadm -Ln

    查看当前ipvs模块中记录的连接(可用于观察转发情况)

     ipvsadm -lnc

    查看ipvs模块的转发情况统计

    ipvsadm -Ln --stats | --rate

    lvs超时配置

    查看lvs的超时时间

    ipvsadm -L --timeout

    优化连接超时时间

    ipvsadm --set 1 10 300

    这里的TCP的连接超时时间最好和keepalived中的persistence_timeout超时时间保持一致;persistence_timeout的超时时间表示指定时间内,同ip的请求会转发到同一个服务;

    测试

    正常代理转发

    使用我linux虚拟机的windows宿主机进行测试

    测试vip

    ping 192.168.1.200


    测试vip监听的端口

    telnet 192.168.1.200 80



    请求虚拟IP查看转发的服务



    KeepAlived高可用测试

    停掉主keepalived

    systemctl stop keepalived 

    vip漂移至备服务器


    此时网页访问:192.168.1.200依然能够正常访问;却分发依然正常



    重启主keepalived

    主服务恢复之后;vip又会自动漂移回主服务

    LVS监控真实服务测试

    查看最新的虚拟ip对应的RealServer的情况

    ipvsadm -l


    可以看出192.168.1.130和192.168.1.131两台正式服务都还在

    测试停掉192.168.1.130



    再次查看虚拟ip对应的RealServer的情况



    可以看出192.168.1.130这台已经挂掉的服务器已经被移除了

    测试访问虚拟ip



    所有的访问都只会转发到131的真实服务器

    恢复192.168.1.130

    lvs又会自动监控并加入192.168.1.130



    常见问题

    裂脑

    主备keepalived服务器同时出现了VIP;导致vip无法正常使用

    常见原因为防火墙配置所致导致多播心跳失败

    vip能ping通,但是vip监听的端口不通

    第一个原因:nginx1和nginx2两台服务器的服务没有正常启动

    第二个原因:请参考上面Nginx服务器那一大项中所说的配置,可能没有配置好

    vip ping不通

    核对是否出现裂脑

    核对keepalived的配置是否正确


    参考文章,感谢原作者

    https://blog.csdn.net/lupengfei1009/article/details/86514445

    https://www.linuxidc.com/Linux/2016-03/129232.htm

    '); +INSERT INTO `ape_document_article` VALUES (74, '

    1.准备工作。

    准备三台虚拟机

    nginx负载均衡器 192.168.0.204

    两台nginx主机 192.168.0202/192.168.0.203

    1.1 关闭防火墙

    所有主机上关闭防火墙,仅部署测试用,具体配置请自行参考

    systemctl stop firewalld\r\nsystemctl disable firewalld

    1.2 所有主机安装nginx

    yum install epel-release -y\r\nyum install nginx -y

    2.Nginx负载均衡的集中方式介绍

    2.1 轮询

    轮询方式是Nginx负载默认的方式,顾名思义,所有请求都按照时间顺序分配到不同的服务上,如果服务Down掉,可以自动剔除,如下配置后轮训10001服务和10002服务。

    upstream  cluster {\r\n       server   192.168.0.202;\r\n       server   192.168.0.203;\r\n}

    2.2 权重

    指定每个服务的权重比例,weight和访问比率成正比,通常用于后端服务机器性能不统一,将性能好的分配权重高来发挥服务器最大性能,如下配置后10002服务的访问比率会是10001服务的二倍。

    upstream  cluster {\r\n       server   192.168.0.202 weight=1;\r\n       server   192.168.0.203 weight=2;\r\n}

    2.3 iphash

    每个请求都根据访问iphash结果分配,经过这样的处理,每个访客固定访问一个后端服务,如下配置(ip_hash可以和weight配合使用)。

    upstream  cluster {\r\n       ip_hash;\r\n       server   192.168.0.202 weight=1;\r\n       server   192.168.0.203 weight=2;\r\n}

    2.4 最少连接

    将请求分配到连接数最少的服务上。

    upstream  cluster {\r\n       least_conn;\r\n       server   192.168.0.202 weight=1;\r\n       server   192.168.0.203 weight=2;\r\n}

    2.5 fair

    按后端服务器的响应时间来分配请求,响应时间短的优先分配。

    upstream  cluster {\r\n       server   192.168.0.202 weight=1;\r\n       server   192.168.0.203 weight=2;\r\n       fair;  \r\n}

    3.Nginx配置

    以轮训为例,如下是nginx.conf完整代码。

    worker_processes  1;\r\nevents {\r\nworker_connections  1024;\r\n}\r\nhttp {\r\n   upstream  cluster {\r\n       server   192.168.0.202;\r\n       server   192.168.0.203;\r\n   }\r\n \r\n   server {\r\n       listen       10000;\r\n       server_name  localhost;\r\n \r\n       location / {\r\n        proxy_pass http://cluster;\r\n        proxy_redirect default;\r\n      }\r\n    }\r\n}

    4.测试

    重启nginx,第一次访问192.168.0.204如图所示,

    \"微信图片_20200404154222.png\"

    在次访问如图所示

    \"微信图片_20200404154231.png\"

    如果要修改负载均衡算法修改对应upstream模块即可。

    '); +INSERT INTO `ape_document_article` VALUES (75, '

    黑白css代码

    html{-webkit-filter: grayscale(100%);-moz-filter: grayscale(100%);-ms-filter: grayscale(100%);-o-filter: grayscale(100%);filter: grayscale(100%);filter: gray; }
    '); +INSERT INTO `ape_document_article` VALUES (76, '

    前言

    最近帮朋友的公司部署了一套分流+水印的直播系统

    顺手打包成docker镜像,方便大家需要用到的时候开箱即用,不需要百度一些零碎的文章
    也可做简单的直播服务,只需调整配置文件便可达到你的需求.

    需求:将直播流分流到两个云厂商的直播云,一个有水印,一个无水印。使用hls播放

    朋友需求的拓扑示意图:

    \"68747470733a2f2f63646e2e61723431342e636f6d2f61723431342d6e67696e782d72746d702e706e67.png\"

    当前拓扑示意图(阿里云和腾讯云不方便放出推流和拉流地址,有兴趣的同学可以去申请玩一下)

    \"68747470733a2f2f63646e2e61723431342e636f6d2f6e67696e782d6c6976652d736572766963652e706e673f613d31

    docker-nginx-rtmp-ffmpeg

    基于docker-nginx-rtmp进行配置部署,这篇文章的意义是实现直播分流及直播画面水印.

    部署运行

    服务器

    $ yum -y install docker #安装docker\r\n$ systemctl enable docker #配置开机启动\r\n$ systemctl start docker #启动docker服务
    #如果速度慢可使用阿里云:docker pull registry.cn-shenzhen.aliyuncs.com/ar414/nginx-rtmp-ffmpeg:v1\r\n$ docker pull ar414/nginx-rtmp-ffmpeg\r\n$ docker run -it -d -p 1935:1935 -p 8080:80 --rm ar414/nginx-rtmp-ffmpeg
    rtmp://:1935/stream/$STREAM_NAME

    将证书复制到容器内,并在容器内修改nginx.conf配置文件,然后重新commit(操作容器内的文件都需要重新commit才会生效)

    #/etc/nginx/nginx.conf\r\nlisten 443 ssl;\r\nssl_certificate     /opt/certs/example.com.crt;\r\nssl_certificate_key /opt/certs/example.com.key;

    OBS配置

    \"68747470733a2f2f63646e2e61723431342e636f6d2f6f62732d636f6e6669672e706e67.png\"

    观看测试

    HLS播放测试工具:http://player.alicdn.com/aliplayer/setting/setting.html (如果配置了证书则使用https)


    \"68747470733a2f2f63646e2e61723431342e636f6d2f61723431342d686c732d776d2e706e67.png\"

    无水印:http://:8080/hls/ar414.m3u8

    \"68747470733a2f2f63646e2e61723431342e636f6d2f61723431342d686c732e706e67.png\"


    RTMP测试工具:PotPlayer

    \"aHR0cHM6Ly9tbWJpei5xcGljLmNuL21tYml6X3BuZy9RRnpSZHo5bGliRWJhaWFiY3ZqcUU0RXBlR0tZNEJxTW1UaWFIYWcyM3hGR25MdWRlVmpSNXFZS1RGUEhqZ2NNbU1LNTdFcWJ0UU5LY3NJZmxpYjFvM2RCa1EvNjQw.jpg\"

    * 有水印:需要分流到其他服务器上\r\n

    配置文件简解(分流、水印及水印位置)

    完整配置文件
    rtmp {\r\n    server {\r\n        listen 1935; #端口\r\n        chunk_size 4000;\r\n        #RTMP 直播流配置\r\n        application stream {\r\n            live on;\r\n            #添加水印及分流,这次方便测试直接分流到当前服务器hls\r\n            #实际生产一般都分流到直播云(腾讯云、阿里云、ucloud)\r\n            #只需把需要分流的地址替换即可\r\n            #有水印:rtmp://localhost:1935/hls/$name_wm\r\n            #无水印:rtmp://localhost:1935/hls/$name\r\n            exec ffmpeg -i rtmp://localhost:1935/stream/$name -i /opt/images/ar414.png\r\n              -filter_complex \"overlay=10:10,split=1[ar414]\"\r\n              -map \'[ar414]\' -map 0:a -s 1920x1080 -c:v libx264 -c:a aac -g 30 -r 30 -tune zerolatency -preset veryfast -crf 23 -f flv rtmp://localhost:1935/hls/$name_wm\r\n              -c:a libfdk_aac -b:a 128k -c:v libx264 -b:v 2500k -f flv -g 30 -r 30 -s 1920x1080 -preset superfast -profile:v baseline rtmp://localhost:1935/hls/$name;\r\n        }\r\n\r\n        application hls {\r\n            live on;\r\n            hls on;\r\n            hls_fragment 5;\r\n            hls_path /opt/data/hls;\r\n        }\r\n    }\r\n}
    application stream {\r\n    live on;\r\n    #分流至本机hls           \r\n    exec ffmpeg -i rtmp://localhost:1935/stream/$name -i /opt/images/ar414.png\r\n      -filter_complex \"overlay=10:10,split=1[ar414]\"\r\n      -map \'[ar414]\' -map 0:a -s 1920x1080 -c:v libx264 -c:a aac -g 30 -r 30 -tune zerolatency -preset veryfast -crf 23 -f flv rtmp://localhost:1935/hls/$name_wm\r\n      -c:a libfdk_aac -b:a 128k -c:v libx264 -b:v 2500k -f flv -g 30 -r 30 -s 1920x1080 -preset superfast -profile:v baseline rtmp://localhost:1935/hls/$name;\r\n    \r\n    #分流至腾讯云\r\n    exec ffmpeg -i rtmp://localhost:1935/stream/$name -i /opt/images/ar414.png\r\n      -filter_complex \"overlay=10:10,split=1[ar414]\"\r\n      -map \'[ar414]\' -map 0:a -s 1920x1080 -c:v libx264 -c:a aac -g 30 -r 30 -tune zerolatency -preset veryfast -crf 23 -f flv rtmp://live-push.tencent.com/stream/$name_wm\r\n      -c:a libfdk_aac -b:a 128k -c:v libx264 -b:v 2500k -f flv -g 30 -r 30 -s 1920x1080 -preset superfast -profile:v baseline rtmp://live-push.tencent.com/stream/$name;\r\n\r\n    #分流至阿里云\r\n    exec ffmpeg -i rtmp://localhost:1935/stream/$name -i /opt/images/ar414.png\r\n      -filter_complex \"overlay=10:10,split=1[ar414]\"\r\n      -map \'[ar414]\' -map 0:a -s 1920x1080 -c:v libx264 -c:a aac -g 30 -r 30 -tune zerolatency -preset veryfast -crf 23 -f flv rtmp://live-push.aliyun.com/stream/$name_wm\r\n      -c:a libfdk_aac -b:a 128k -c:v libx264 -b:v 2500k -f flv -g 30 -r 30 -s 1920x1080 -preset superfast -profile:v baseline rtmp://live-push.aliyun.com/stream/$name;\r\n}

    水印位置

    水印图片位置 overlay 值

    左上角
     10:10
    右上角 
    main_w-overlay_w-10:10
    左下角
     10:main_h-overlay_h-10
    右下角 
    main_w-overlay_w-10 : main_h-overlay_h-10

    overlay 参数

    参数 说明

    main_w 视频单帧图像宽度(当前配置文件 1920)

    main_h 视频单帧图像高度(当前配置文件 1080)

    overlay_w 水印图片的宽度

    overlay_h 水印图片的高度


    转载自 https://github.com/ar414-com/nginx-rtmp-ffmpeg-conf

    '); +INSERT INTO `ape_document_article` VALUES (77, '

    PHP里有个函数很有用。这是在最近的开发中才逐渐用到的。 
    int ignore_user_abort ( [bool setting] ) 
    这个函数的作用是指示服务器端在远程客户端关闭连接后是否继续执行下面的脚本。

    setting 参数是一个可选参数。如设置为True,则表示如果用户停止脚本运行,仍然不影响脚本的运行(即:脚本将持续执行);如果设置为False,则表示当用户停止运行脚本程序时,脚本程序将停止运行。

    下面这个例子,在用户关闭浏览器后,该脚本仍然后在服务器上继续执行:

    1. <?php
    2. ignore_user_abort(); // 后台运行
    3. set_time_limit(0); // 取消脚本运行时间的超时上限
    4. do{
    5. sleep(60); // 休眠1分钟
    6. }while(true);
    7. ?>


    除非在服务器上关闭这个程序,否则这断代码将永远执行下去。

    -------------------------------------------------------------------------

    1. <?php
    2.    ignore_user_abort(); // 后台运行
    3.    set_time_limit(0); // 取消脚本运行时间的超时上限
    4.    echo \'start.\';
    5.    while(!file_exists(\'close.txt\')){
    6.     $fp = fopen(\'test.txt\',\'a+\');
    7.     fwrite($fp,date(\"Y-m-d H:i:s\") . \" 成功了!rn\");
    8.     fclose($fp);
    9.     sleep(10);
    10.    }
    11.    echo \'end.\';
    12. ?>

    http://www.thinksaas.cn/topics/0/3/3910.html

    '); +INSERT INTO `ape_document_article` VALUES (78, '

    介绍

    前文已经说了explain命令的大部分参数,图解:实战EXPLAIN这篇文章把explain的key_len参数分享完,接着分享最左前缀原则,建立如下的表,其中name列和address列都建立了索引

    CREATE TABLE `teacher` (\r\n  `id` int(10) NOT NULL,\r\n  `name` char(20) NOT NULL,\r\n  `address` varchar(100) DEFAULT NULL,\r\n  PRIMARY KEY (`id`),\r\n  KEY `idx_name` (`name`),\r\n  KEY `idx_addr` (`address`)\r\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;

    执行如下命令

    explain select * from teacher where name = \"张三\"

    \"20181104221050891.png\"

    explain select * from teacher where address = \"北京\"

    \"20181104221215891.png\"

    问题来了,这些key_len是怎么算出来的呢?

    key_len

    key_len表示索引使用的字节数,根据这个值,就可以判断索引使用情况,特别是在组合索引的时候,判断所有的索引字段是否都被查询用到

    字符串类型

    \"20181104205738871.png\"

    char和varchar跟字符编码也有密切的联系

    latin1占用一个字节,gbk占用2个字节,utf8占用3个字节,utf8mb4占用4个字节(不同字符编码占用的存储空间不同)

    字符类型-索引字段为char类型+不可为Null时

    char(n)=n*(utf8mb4=4,utf8=3,gbk=2,latin1=1)

    所以上面第一个列子(查询name=张三)的key_len为20*3=60

    下文中为了描述方便,编码类型默认为utf8

    字符类型-索引字段为char类型+允许为Null时

    char(n)=n*3+1(允许null,是否为空的标记)

    字符类型-索引字段为varchar类型+不可为Null时

    varchar(n)=n*3+2(变长列,记录当前数据存了多少)

    字符类型-索引字段为varchar类型+允许为Null时

    varchar(n)=n*3+1(允许null)+2(变长列)

    所以上面第二个例子(查询住址=北京)的key_len为100*3+1+2=303

    \"20181104205754996.png\"

    \"20181104205738871.png\"

    datetime类型在5.6中字段长度是5个字节,datetime类型在5.5中字段长度是8个字节

    整数/浮点数/时间类型的索引长度

    Not Null=字段本身的长度

    Null=字段本身的长度+1

    最左前缀原则

    查询

    主要针对组合索引,满足如下2个条件即可满足左前缀原则

    1. 需要查询的列和组合索引的列顺序一致
    2. 查询不要跨列

    构造数据如下,其中在name,address,country上建了联合索引

    CREATE TABLE `people` (\r\n  `name` varchar(50) NOT NULL,\r\n  `address` varchar(50) NOT NULL,\r\n  `country` varchar(50) NOT NULL,\r\n  KEY `idx_name_addr_country` (`name`,`address`,`country`)\r\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;

    先简单举个例子,然后总结一下

    explain select * from people where name = \"jack\" and address = \"beijing\" and country = \"china\"

    \"20181107135429885.png\"

    type为ref,key_len为456=(50*3+2)*3,联合索引的所有列都使用了

    explain select * from people where name = \"jack\"

    \"20181107135231501.png\"

    type为ref,key_len为152=50*3+2,联合索引只使用了name列

    explain select * from people where address = \"beijing\"

    \"2018110713584572.png\"

    type为index,并没有走索引,简单说一下index和ref的区别

    index:这种类型表示mysql会对整个该索引进行扫描。要想用到这种类型的索引,对这个索引并无特别要求,只要是索引,或者某个联合索引的一部分,mysql都可能会采用index类型的方式扫描。但是呢,缺点是效率不高,mysql会从索引中的第一个数据一个个的查找到最后一个数据,直到找到符合判断条件的某个索引。所以,上述语句会触发索引

    ref:这种类型表示mysql会根据特定的算法快速查找到某个符合条件的索引,而不是会对索引中每一个数据都进行一一的扫描判断,也就是所谓你平常理解的使用索引查询会更快的取出数据。而要想实现这种查找,索引却是有要求的,要实现这种能快速查找的算法,索引就要特定的数据结构。简单说,也就是索引字段的数据必须是有序的,才能实现这种类型的查找,才能利用到索引。

    总结几个典型的例子,联合索引为

    key idx_a_b_c(a,b,c)

    sql 是否使用索引

    where a = x and b = x and c = x	是\r\nwhere a = x and b = x	是,部分索引\r\nwhere a = x	是,部分索引\r\nwhere b = x	否,不包含最左列name\r\nwhere b = x and c = x	否,不包含最左列name

    排序

    最左前缀原则不仅用在查询中,还能用在排序中。MySQL中,有两种方式生成有序结果集:

    通过有序索引顺序扫描直接返回有序数据

    Filesort排序,对返回的数据进行排序

    因为索引的结构是B+树,索引中的数据是按照一定顺序进行排列的,所以在排序查询中如果能利用索引,就能避免额外的排序操作。EXPLAIN分析查询时,Extra显示为Using index。

    所有不是通过索引直接返回排序结果的操作都是Filesort排序,也就是说进行了额外的排序操作。EXPLAIN分析查询时,Extra显示为Using filesort,当出现Using filesort时对性能损耗较大,所以要尽量避免Using filesort

    还是先举2个例子,然后总结

    explain select * from people order by name

    \"2018110715593476.png\"

    Extra列只有Using index,即根据索引顺序进行扫描

    explain select * from people order by address

    \"20181107162452889.png\"

    Extra列有Using filesort

    总结:假如说有如下联合索引,key idx_a_b_c(a,b,c)

    order by 能使用索引排序

    order by a\r\norder by a,b\r\norder by a,b,c\r\norder by a desc, b desc, c desc\r\nwhere a = const order by b,c\r\nwhere a = const and b = const order by c\r\nwhere a = const and b > const order by b,c

    order by 不能使用索引进行排序

    order by b\r\norder by c\r\norder by b, c\r\norder by a asc, b desc, c desc //排序不一致\r\nwhere g = const order by b,c //丢失a索引\r\nwhere a = const order by c //丢失b索引\r\nwhere a = const order by a,d //d不是索引的一部分\r\nwhere a in (...) order by b,c //范围查询

    有时间会单开一篇文章介绍order by优化,这里只做个粗浅的介绍

    联合索引特性

    增加开销。建一个联合索引(col1,col2,col3),实际相当于建了(col1),(col1,col2),(col1,col2,col3)三个索引。每多一个索引,都会增加写操作的开销和磁盘空间的开销。对于大量数据的表,使用联合索引会大大增加开销!

    覆盖索引。对联合索引(col1,col2,col3),如果有如下的sql: select col1,col2,col3 from test where col1=1 and col2=2。那么MySQL可以直接通过遍历索引取得数据,而无需回表,这了很多的随机io操作。io操作,特别的随机io其实是dba主要的优化策略。所以,在真正的实际应用中,覆盖索引是主要的提升性能的优化手段之一。

    效率高。索引列越多,通过索引筛选出的数据越少。有1000W条数据的表,有如下sql:select from table where col1=1 and col2=2 and col3=3,假设假设每个条件可以筛选出10%的数据,如果只有单值索引,那么通过该索引能筛选出1000W10%=100w条数据,然后再回表从100w条数据中找到符合col2=2 and col3= 3的数据,然后再排序,再分页;如果是联合索引,通过索引筛选出1000w*10%*10% *10%=1w,效率提升可想而知!

    '); +INSERT INTO `ape_document_article` VALUES (79, '

    一、supervisor简介

    Supervisor是用Python开发的一套通用的进程管理程序,能将一个普通的命令行进程变为后台daemon,并监控进程状态,异常退出时能自动重启。它是通过fork/exec的方式把这些被管理的进程当作supervisor的子进程来启动,这样只要在supervisor的配置文件中,把要管理的进程的可执行文件的路径写进去即可。也实现当子进程挂掉的时候,父进程可以准确获取子进程挂掉的信息的,可以选择是否自己启动和报警。supervisor还提供了一个功能,可以为supervisord或者每个子进程,设置一个非root的user,这个user就可以管理它对应的进程。

    注:本文以centos7为例。

    二、supervisor安装

    1. 配置好yum源后,可以直接安装

      yum install supervisor\r\n

    2. Debian/Ubuntu可通过apt安装

      apt-get install supervisor\r\n

    3. pip安装

      pip install supervisor\r\n

    4. easy_install安装

      easy_install supervisor\r\n

    三、supervisor使用

    supervisor配置文件:/etc/supervisor/supervisord.conf

    注:supervisor的配置文件默认是不全的,不过在大部分默认的情况下,上面说的基本功能已经满足。

    子进程配置文件路径:/etc/supervisord.d/

    注:默认子进程配置文件为ini格式,可在supervisor主配置文件中修改。

    四、配置文件说明

    supervisor.conf配置文件说明:

    [unix_http_server]\r\nfile=/tmp/supervisor.sock   ;UNIX socket 文件,supervisorctl 会使用\r\n;chmod=0700                 ;socket文件的mode,默认是0700\r\n;chown=nobody:nogroup       ;socket文件的owner,格式:uid:gid\r\n \r\n;[inet_http_server]         ;HTTP服务器,提供web管理界面\r\n;port=127.0.0.1:9001        ;Web管理后台运行的IP和端口,如果开放到公网,需要注意安全性\r\n;username=user              ;登录管理后台的用户名\r\n;password=123               ;登录管理后台的密码\r\n \r\n[supervisord]\r\nlogfile=/tmp/supervisord.log ;日志文件,默认是 $CWD/supervisord.log\r\nlogfile_maxbytes=50MB        ;日志文件大小,超出会rotate,默认 50MB,如果设成0,表示不限制大小\r\nlogfile_backups=10           ;日志文件保留备份数量默认10,设为0表示不备份\r\nloglevel=info                ;日志级别,默认info,其它: debug,warn,trace\r\npidfile=/tmp/supervisord.pid ;pid 文件\r\nnodaemon=false               ;是否在前台启动,默认是false,即以 daemon 的方式启动\r\nminfds=1024                  ;可以打开的文件描述符的最小值,默认 1024\r\nminprocs=200                 ;可以打开的进程数的最小值,默认 200\r\n \r\n[supervisorctl]\r\nserverurl=unix:///tmp/supervisor.sock ;通过UNIX socket连接supervisord,路径与unix_http_server部分的file一致\r\n;serverurl=http://127.0.0.1:9001 ; 通过HTTP的方式连接supervisord\r\n \r\n; [program:xx]是被管理的进程配置参数,xx是进程的名称\r\n[program:xx]\r\ncommand=/opt/apache-tomcat-8.0.35/bin/catalina.sh run  ; 程序启动命令\r\nautostart=true       ; 在supervisord启动的时候也自动启动\r\nstartsecs=10         ; 启动10秒后没有异常退出,就表示进程正常启动了,默认为1秒\r\nautorestart=true     ; 程序退出后自动重启,可选值:[unexpected,true,false],默认为unexpected,表示进程意外杀死后才重启\r\nstartretries=3       ; 启动失败自动重试次数,默认是3\r\nuser=tomcat          ; 用哪个用户启动进程,默认是root\r\npriority=999         ; 进程启动优先级,默认999,值小的优先启动\r\nredirect_stderr=true ;stderr重定向到stdout,默认false\r\nstdout_logfile_maxbytes=20MB  ; stdout 日志文件大小,默认50MB\r\nstdout_logfile_backups = 20   ; stdout 日志文件备份数,默认是10\r\n; stdout 日志文件,需要注意当指定目录不存在时无法正常启动,所以需要手动创建目录(supervisord 会自动创建日志文件)\r\nstdout_logfile=/opt/apache-tomcat-8.0.35/logs/catalina.out\r\nstopasgroup=false     ;默认为false,进程被杀死时,是否向这个进程组发送stop信号,包括子进程\r\nkillasgroup=false     ;默认为false,向进程组发送kill信号,包括子进程\r\n \r\n;包含其它配置文件\r\n[include]\r\nfiles = relative/directory/*.ini    ;可以指定一个或多个以.ini结束的配置文件\r\n

    子进程配置文件说明:

    给需要管理的子进程(程序)编写一个配置文件,放在/etc/supervisor.d/目录下,以.ini作为扩展名(每个进程的配置文件都可以单独分拆也可以把相关的脚本放一起)。如任意定义一个和脚本相关的项目名称的选项组(/etc/supervisord.d/test.conf):

    #项目名\r\n[program:blog]\r\n#脚本目录\r\ndirectory=/opt/bin\r\n#脚本执行命令\r\ncommand=/usr/bin/python /opt/bin/test.py\r\n\r\n#supervisor启动的时候是否随着同时启动,默认True\r\nautostart=true\r\n#当程序exit的时候,这个program不会自动重启,默认unexpected,设置子进程挂掉后自动重启的情况,有三个选项,false,unexpected和true。如果为false的时候,无论什么情况下,都不会被重新启动,如果为unexpected,只有当进程的退出码不在下面的exitcodes里面定义的\r\nautorestart=false\r\n#这个选项是子进程启动多少秒之后,此时状态如果是running,则我们认为启动成功了。默认值为1\r\nstartsecs=1\r\n\r\n#脚本运行的用户身份 \r\nuser = test\r\n\r\n#日志输出 \r\nstderr_logfile=/tmp/blog_stderr.log \r\nstdout_logfile=/tmp/blog_stdout.log \r\n#把stderr重定向到stdout,默认 false\r\nredirect_stderr = true\r\n#stdout日志文件大小,默认 50MB\r\nstdout_logfile_maxbytes = 20M\r\n#stdout日志文件备份数\r\nstdout_logfile_backups = 20\r\n
    子进程配置示例:

    #说明同上\r\n[program:test] \r\ndirectory=/opt/bin \r\ncommand=/opt/bin/test\r\nautostart=true \r\nautorestart=false \r\nstderr_logfile=/tmp/test_stderr.log \r\nstdout_logfile=/tmp/test_stdout.log \r\n#user = test  \r\n

    五、supervisor命令说明

    常用命令

    supervisorctl status        //查看所有进程的状态\r\nsupervisorctl stop es       //停止es\r\nsupervisorctl start es      //启动es\r\nsupervisorctl restart       //重启es\r\nsupervisorctl update        //配置文件修改后使用该命令加载新的配置\r\nsupervisorctl reload        //重新启动配置中的所有程序\r\n

    注:把es换成all可以管理配置中的所有进程。直接输入supervisorctl进入supervisorctl的shell交互界面,此时上面的命令不带supervisorctl可直接使用。

    注意事项

    使用supervisor进程管理命令之前先启动supervisord,否则程序报错。
    使用命令supervisord -c /etc/supervisor/supervisord.conf启动。
    若是centos7:

    systemctl start supervisord.service     //启动supervisor并加载默认配置文件\r\nsystemctl enable supervisord.service    //将supervisor加入开机启动项\r\n
    常见问题
    1. unix:///var/run/supervisor.sock no such file
      问题描述:安装好supervisor没有开启服务直接使用supervisorctl报的错
      解决办法:supervisord -c /etc/supervisor/supervisord.conf

    2. command中指定的进程已经起来,但supervisor还不断重启
      问题描述:command中启动方式为后台启动,导致识别不到pid,然后不断重启,这里使用的是elasticsearch,command指定的是$path/bin/elasticsearch -d
      解决办法:supervisor无法检测后台启动进程的pid,而supervisor本身就是后台启动守护进程,因此不用担心这个

    3. 启动了多个supervisord服务,导致无法正常关闭服务
      问题描述:在运行supervisord -c /etc/supervisor/supervisord.conf之前,直接运行过supervisord -c /etc/supervisord.d/xx.conf导致有些进程被多个superviord管理,无法正常关闭进程。
      解决办法:使用ps -fe | grep supervisord查看所有启动过的supervisord服务,kill相关的进程。

    更多信息请移步Supervisor官网:http://supervisord.org


    转载自简书

    作者:风吹我已散博客

    链接:https://www.jianshu.com/p/0b9054b33db3

    '); +INSERT INTO `ape_document_article` VALUES (80, '

    因为mysql5.7默认配置配置问题提示

    E\r\nRROR 1292 (22007): Incorrect datetime value: \'1970-01-01 08:00:00\' for column \'time\' at row 1
     SQLSTATE[42000]: Syntax error or access violation: 1067 Invalid default val\r\n  ue for \'license_validity\'

    解决办法

    临时修改sql_model

    public function change()
    {
    $this->execute(\' set session sql_mode=\\\'ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION\\\';\');
    }
    '); +INSERT INTO `ape_document_article` VALUES (81, '
      //--------------------------------------------------------------------------------------\r\n  /**\r\n    * 函数的含义说明:CURL发送post请求    获取数据\r\n    * \r\n    * @access public \r\n    * @param str          $url     发送接口地址\r\n    * @param array/json   $data    要发送的数据  \r\n    * @param false/true   $json    false $data数组格式  true $data json格式\r\n    * @return  返回json数据\r\n     */   \r\n    public function httpPostRequest($url, $data = null,$json = FALSE){\r\n        //创建了一个curl会话资源,成功返回一个句柄;\r\n        $curl = curl_init();\r\n        //设置url\r\n        curl_setopt($curl, CURLOPT_URL, $url);\r\n        //设置为FALSE 禁止 cURL 验证对等证书(peer’s certificate)\r\n        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);\r\n        //设置为 1 是检查服务器SSL证书中是否存在一个公用名(common name)\r\n        curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE);\r\n        if (!empty($data)){\r\n            //设置请求为POST\r\n            curl_setopt($curl, CURLOPT_POST, 1);\r\n            //curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 60); //最长的可忍受的连接时间\r\n            //设置POST的数据域\r\n            curl_setopt($curl, CURLOPT_POSTFIELDS, $data);\r\n            if($json){\r\n                curl_setopt($curl, CURLOPT_HEADER, 0);\r\n                curl_setopt($curl, CURLOPT_HTTPHEADER, array(\r\n                        \'Content-Type: application/json; charset=utf-8\',\r\n                        \'Content-Length: \' . strlen($data)\r\n                    )\r\n                );\r\n\r\n            }\r\n        }\r\n        //设置是否将响应结果存入变量,1是存入,0是直接输出\r\n        curl_setopt($curl, CURLOPT_RETURNTRANSFER, TRUE);\r\n        //然后将响应结果存入变量\r\n        $output = curl_exec($curl);\r\n        //关闭这个curl会话资源\r\n        curl_close($curl);\r\n        return $output;\r\n    }\r\n  //--------------------------------------------------------------------------------------\r\n  /**  \r\n    * 函数的含义说明:CURL发送get请求    获取数据\r\n    * \r\n    * @access public \r\n    * @param str $url 发送接口地址  https://api.douban.com/v2/movie/in_theaters?city=广州&start=0&count=10\r\n    * @return  返回json数据\r\n     */ \r\n     public function httpGetRequest($url){\r\n\r\n        $curl = curl_init(); // 启动一个CURL会话\r\n        curl_setopt($curl, CURLOPT_URL, $url);\r\n        curl_setopt($curl, CURLOPT_HEADER, 0);\r\n        curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);\r\n        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false); // 跳过证书检查\r\n        //curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, true);  // 从证书中检查SSL加密算法是否存在\r\n        $output = curl_exec($curl);     //返回api的json对象\r\n        //关闭URL请求\r\n        curl_close($curl);\r\n        return $output;    //返回json对象\r\n    }\r\n\r\n\r\n//--------------------------------------------------------------------------------------\r\n/**  \r\n  * 函数的含义说明:模仿登录带cookie值抓取页面\r\n  * @access public \r\n  * @param  string   \r\n  * @return string   \r\n  */\r\n$data=array(\'username\' => \'promonkey\', \r\n    \'password\' => \'1q2w3e\',\r\n    \'remember\'=>1);\r\n$data=\'username=zjzhoufy@126.com&password=1q2w3e&remember=1\';\r\n$curlobj = curl_init();         // 初始化\r\ncurl_setopt($curlobj, CURLOPT_URL, \"http://www.imooc.com/user/login\");      // 设置访问网页的URL\r\ncurl_setopt($curlobj, CURLOPT_RETURNTRANSFER, true);            // 执行之后不直接打印出来\r\n\r\n// Cookie相关设置,这部分设置需要在所有会话开始之前设置\r\ndate_default_timezone_set(\'PRC\'); // 使用Cookie时,必须先设置时区\r\ncurl_setopt($curlobj, CURLOPT_COOKIESESSION, TRUE); \r\ncurl_setopt($curlobj, CURLOPT_HEADER, 0); \r\ncurl_setopt($curlobj, CURLOPT_FOLLOWLOCATION, 1); // 这样能够让cURL支持页面链接跳转\r\n\r\ncurl_setopt($curlobj, CURLOPT_POST, 1);  \r\ncurl_setopt($curlobj, CURLOPT_POSTFIELDS, $data);  \r\ncurl_setopt($curlobj, CURLOPT_HTTPHEADER, array(\"application/x-www-form-urlencoded; charset=utf-8\", \r\n    \"Content-length: \".strlen($data)\r\n    )); \r\ncurl_exec($curlobj);    // 执行\r\ncurl_setopt($curlobj, CURLOPT_URL, \"http://www.imooc.com/space/index\");\r\ncurl_setopt($curlobj, CURLOPT_POST, 0);  \r\ncurl_setopt($curlobj, CURLOPT_HTTPHEADER, array(\"Content-type: text/xml\"\r\n    )); \r\n$output=curl_exec($curlobj);    // 执行\r\ncurl_close($curlobj);       // 关闭cURL\r\necho $output;\r\n//--------------------------------------------------------------------------------------\r\n/**  \r\n  * 函数的含义说明:模仿登录获取cookie值抓取页面\r\n  * @access public \r\n  * @param  string   \r\n  * @return string   \r\n  */\r\n$data=\'username=demo_peter@126.com&password=123qwe&remember=1\';\r\n$curlobj = curl_init();         // 初始化\r\ncurl_setopt($curlobj, CURLOPT_URL, \"http://www.imooc.com/user/login\");      // 设置访问网页的URL\r\ncurl_setopt($curlobj, CURLOPT_RETURNTRANSFER, true);            // 执行之后不直接打印出来\r\n\r\n// Cookie相关设置,这部分设置需要在所有会话开始之前设置\r\ndate_default_timezone_set(\'PRC\'); // 使用Cookie时,必须先设置时区\r\ncurl_setopt($curlobj, CURLOPT_COOKIESESSION, TRUE); \r\ncurl_setopt($curlobj, CURLOPT_HEADER, 0); \r\n// 注释掉这行,因为这个设置必须关闭安全模式 以及关闭open_basedir,对服务器安全不利\r\n//curl_setopt($curlobj, CURLOPT_FOLLOWLOCATION, 1);  \r\n\r\ncurl_setopt($curlobj, CURLOPT_POST, 1);  \r\ncurl_setopt($curlobj, CURLOPT_POSTFIELDS, $data);  \r\ncurl_setopt($curlobj, CURLOPT_HTTPHEADER, array(\"application/x-www-form-urlencoded; charset=utf-8\", \r\n    \"Content-length: \".strlen($data)\r\n    )); \r\ncurl_exec($curlobj);    // 执行\r\ncurl_setopt($curlobj, CURLOPT_URL, \"http://www.imooc.com/space/index\");\r\ncurl_setopt($curlobj, CURLOPT_POST, 0);  \r\ncurl_setopt($curlobj, CURLOPT_HTTPHEADER, array(\"Content-type: text/xml\"\r\n    )); \r\n$output=curl_redir_exec($curlobj);  // 执行\r\ncurl_close($curlobj);           // 关闭cURL\r\necho $output;\r\n//------------------------------------------------------------------------------------\r\n        CURL登录携带cookie获取首页数据配置\r\n    date_default_timezone_set(\'PRC\');//使用cookie,必须先设置时区\r\n    curl_setopt($curlobj,CURLOPT_COOKIESESSION,RURE);\r\n    curl_setopt($curlobj,CURLOPT_COOKIEFILE,\"cookiefile\");\r\n    curl_setopt($curlobj,CURLOPT_COOKIEJAR,\"cookiefile\");\r\n    curl_setopt($curlobj,CURLOPT_COOKIE,session_name().\'=\'.session_id());\r\n    curl_setopt($curlobj,CURLOPT_HEADER,0);\r\n    curl_setopt($curlobj,CURLOPT_FOLLOWLOCATION,1);//让CURL支持页面跳转\r\n\r\n//------------------------------------------------------------------------------------\r\n/**\r\n * 实例描述:从FTP服务器下载一个文件到本地\r\n */\r\n$curlobj = curl_init(); \r\ncurl_setopt($curlobj, CURLOPT_URL, \"ftp://192.168.1.100/downloaddemo.txt\");  \r\ncurl_setopt($curlobj, CURLOPT_HEADER, 0); \r\ncurl_setopt($curlobj, CURLOPT_RETURNTRANSFER, 1);  \r\ncurl_setopt($curlobj, CURLOPT_TIMEOUT, 300); // times out after 300s\r\ncurl_setopt($curlobj, CURLOPT_USERPWD, \"peter.zhou:123456\");//FTP用户名:密码\r\n// Sets up the output file\r\n$outfile = fopen(\'dest.txt\', \'wb\');//保存到本地的文件名\r\ncurl_setopt($curlobj, CURLOPT_FILE, $outfile);\r\n\r\n$rtn = curl_exec($curlobj);  \r\nfclose($outfile); \r\nif(!curl_errno($curlobj)){\r\n    // $info = curl_getinfo($curlobj); \r\n    // print_r($info);\r\n    echo \"RETURN: \" . $rtn;  \r\n} else {\r\n  echo \'Curl error: \' . curl_error($curlobj);\r\n}\r\ncurl_close($curlobj);\r\n\r\n//------------------------------------------------------------------------------------\r\n/**\r\n * 代码实例-PHP-cURL实战\r\n * 实例描述:把本地文件上传到FTP服务器上\r\n */\r\n$curlobj = curl_init(); \r\n$localfile = \'ftp01.php\';\r\n$fp = fopen($localfile, \'r\');\r\n\r\ncurl_setopt($curlobj, CURLOPT_URL, \"ftp://192.168.1.100/ftp01_uploaded.php\");  \r\ncurl_setopt($curlobj, CURLOPT_HEADER, 0); \r\ncurl_setopt($curlobj, CURLOPT_RETURNTRANSFER, 1);  \r\ncurl_setopt($curlobj, CURLOPT_TIMEOUT, 300); // times out after 300s\r\ncurl_setopt($curlobj, CURLOPT_USERPWD, \"peter.zhou:123456\");//FTP用户名:密码\r\n\r\ncurl_setopt($curlobj, CURLOPT_UPLOAD, 1);\r\ncurl_setopt($curlobj, CURLOPT_INFILE, $fp);\r\ncurl_setopt($curlobj, CURLOPT_INFILESIZE, filesize($localfile));\r\n$rtn = curl_exec($curlobj);  \r\nfclose($fp); \r\nif(!curl_errno($curlobj)){\r\n    echo \"Uploaded successfully.\";  \r\n} else {\r\n  echo \'Curl error: \' . curl_error($curlobj);\r\n}\r\ncurl_close($curlobj);\r\n\r\n//------------------------------------------------------------------------------------\r\n/**\r\n * 代码实例-PHP-CURL下载文件或者图片\r\n*$url:远程图片路径或文件路径\r\n*$path:本地下载路径\r\n */\r\npublic function download($url, $path = \'images/\')\r\n{\r\n        $ch = curl_init();\r\n        curl_setopt($ch, CURLOPT_URL, $url);\r\n        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);\r\n        curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 30);\r\n        $file = curl_exec($ch);\r\n        curl_close($ch);\r\n        $filename = pathinfo($url, PATHINFO_BASENAME);\r\n        $resource = fopen($path . $filename, \'a\');\r\n        fwrite($resource, $file);\r\n        fclose($resource);\r\n}
    '); +INSERT INTO `ape_document_article` VALUES (82, '

    1. 生成秘钥对

    (1)确定自己是否有公钥

    $ cd ~/.ssh
    $ ls

    查看是否有id_rsa 、id_rsa.push(或者是id_das和id_das.pub一类成对的文件),

    其中有.pub后缀的文件就是公钥另一个对应的就是私钥。

    如果没有上述描述的文件,甚至连.ssh目录都没有,继续。


    (2)用ssh-keygen创建

    $ ssh-keygen -t rsa -C \"邮箱地址\"

    按提示需要依次输入秘钥、密码、密码确认。不是自己服务器请输入密码保证安全,如果自己服务器这里建议全部回车否则之后每次push的时候都需要输入一次秘钥的密码,也是很痛苦的一件事情

    看到以下类似提示就代表本地秘钥已经生成。

    Your public key has been saved in ****\r\nThe key fingerprint is:\r\nSHA256:RAn+oaeba2FZ+8aLlGSwS/U9ZYpPjB74ccYFqu9givw\"邮箱地址\"

     

    2. 设置远程仓库上的公钥

    (1)在终端上查看生成的公钥

    $ cat ~/.ssh/id_rsa.pub

    得到类似下面的一串乱码,这个就是我们的秘钥了。

    ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDIJhA59Wpo3SWJWvAyCARaHyjeB+W6bUNTQamUUlfljYtGrbgLEh3CXyPBUHqLZWiRlJcRKax3rKoeA3GpY6yrKGxtjyJW9WhAIurwVm1FatT5StHQiCJslKBnODbWDZL05MF/O399ZyovDBQ1HE2U779m/fZhOh8+GZKXdfn09Fq9g0f2fYA/bbAANAkFDHryBrfKz/tB2EY+kvMmVrqQFftbg1n19lzfzgQ3gkr4yTFTD5N94SxVhu/KpdHuK+2abLqlkeabIdrWObT+qlf/Xyi0nflkyf309XSL2Xqy4JhSGKR74+6bTyPNF5DKx5HVdxJ6M7Q6RmX5KnTG/Axn\"邮箱地址\"

    (2)在网站上登录git账号,点击头像,选择setting,选择SSH秘钥,粘贴上面全部的乱码(以ssh-rsa开头),点击添加秘钥。

    到这里基本完成了SSH秘钥的设置。尝试使用SSH方法克隆项目,如果依然不行尝试操作第三步操作。


    3. 修改git的remote url

    有些集成了git的开发环境中会自动修改的。

    (1)查看当前的remote url

    $ git remote -v

    (2)修改remote url

    如果是https:打头的地址是https协议,git打头的则是git协议。注意这里必须ssh不能https

    $ git remote set-url origin 对应的协议打头的clone地址

     

    '); +INSERT INTO `ape_document_article` VALUES (83, '

    样例

    <?php\r\n$array1 = array();\r\n$array2 = array(\"green\", \"red\", \"blue\", \"red\");\r\n$result = array_diff($array1, $array2);\r\nprint_r($result);\r\n?>\r\n


    输出结果为空??? 黑人问号,一脸懵逼的去查阅手册发现问题,错误理解函数作用

    array_diff 解释 :对比 array1 和其他一个或者多个数组,返回在 array1 中但是不在其他 array 里的值。

    并不是两个的差集 。。。

    '); +INSERT INTO `ape_document_article` VALUES (84, '

    特殊需求 根绝token自动获取user_id 问题 特殊需求  so 只能 这么处理,不能通过中间件 直接获取request->userInfo 这样获取

    核心思想

    判定action 是否需要验证 

    验证则转换 然后更新 response->poset值,注意由于使用的是response 门面方法  静态调用 so 需求 unset掉才能重新生效获取到 param的值

    '); +INSERT INTO `ape_document_article` VALUES (85, '

    禁止鼠标右键和禁止F12

    $(function(){\r\n    $(document).ready(function(){\r\n        $(document).bind(\"contextmenu\",function(e){\r\n            return false;\r\n        });\r\n    });\r\n\r\n     $(document).keydown(function(e) {\r\n        if (e.keyCode == 123) {\r\n            return false;\r\n        }\r\n        if ((e.ctrlKey) && (e.keyCode == 83)) { //ctrl+s\r\n            return false;\r\n        }\r\n    });\r\n})



    转载自 http://majiameng.com/article/2812.html

    '); +INSERT INTO `ape_document_article` VALUES (86, '

     很多不太懂正则的朋友,在遇到需要用正则校验数据时,往往是在网上去找很久,结果找来的还是不很符合要求。所以我最近把开发中常用的一些正则表达式整理了一下,在这里分享一下。给自己留个底,也给朋友们做个参考。

    一、校验数字的表达式

     1 数字:^[0-9]*$\r\n 2 n位的数字:^\\d{n}$\r\n 3 至少n位的数字:^\\d{n,}$\r\n 4 m-n位的数字:^\\d{m,n}$\r\n 5 零和非零开头的数字:^(0|[1-9][0-9]*)$\r\n 6 非零开头的最多带两位小数的数字:^([1-9][0-9]*)+(.[0-9]{1,2})?$\r\n 7 带1-2位小数的正数或负数:^(\\-)?\\d+(\\.\\d{1,2})?$\r\n 8 正数、负数、和小数:^(\\-|\\+)?\\d+(\\.\\d+)?$\r\n 9 有两位小数的正实数:^[0-9]+(.[0-9]{2})?$\r\n10 有1~3位小数的正实数:^[0-9]+(.[0-9]{1,3})?$\r\n11 非零的正整数:^[1-9]\\d*$^([1-9][0-9]*){1,3}$^\\+?[1-9][0-9]*$\r\n12 非零的负整数:^\\-[1-9][]0-9\"*$  ^-[1-9]\\d*$\r\n13 非负整数:^\\d+$^[1-9]\\d*|0$\r\n14 非正整数:^-[1-9]\\d*|0$^((-\\d+)|(0+))$\r\n15 非负浮点数:^\\d+(\\.\\d+)?$^[1-9]\\d*\\.\\d*|0\\.\\d*[1-9]\\d*|0?\\.0+|0$\r\n16 非正浮点数:^((-\\d+(\\.\\d+)?)|(0+(\\.0+)?))$^(-([1-9]\\d*\\.\\d*|0\\.\\d*[1-9]\\d*))|0?\\.0+|0$\r\n17 正浮点数:^[1-9]\\d*\\.\\d*|0\\.\\d*[1-9]\\d*$^(([0-9]+\\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\\.[0-9]+)|([0-9]*[1-9][0-9]*))$\r\n18 负浮点数:^-([1-9]\\d*\\.\\d*|0\\.\\d*[1-9]\\d*)$^(-(([0-9]+\\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\\.[0-9]+)|([0-9]*[1-9][0-9]*)))$\r\n19 浮点数:^(-?\\d+)(\\.\\d+)?$^-?([1-9]\\d*\\.\\d*|0\\.\\d*[1-9]\\d*|0?\\.0+|0)$

    二、校验字符的表达式

     1 汉字:^[\\u4e00-\\u9fa5]{0,}$\r\n 2 英文和数字:^[A-Za-z0-9]+$^[A-Za-z0-9]{4,40}$\r\n 3 长度为3-20的所有字符:^.{3,20}$\r\n 4 由26个英文字母组成的字符串:^[A-Za-z]+$\r\n 5 由26个大写英文字母组成的字符串:^[A-Z]+$\r\n 6 由26个小写英文字母组成的字符串:^[a-z]+$\r\n 7 由数字和26个英文字母组成的字符串:^[A-Za-z0-9]+$\r\n 8 由数字、26个英文字母或者下划线组成的字符串:^\\w+$ 或 ^\\w{3,20}$\r\n 9 中文、英文、数字包括下划线:^[\\u4E00-\\u9FA5A-Za-z0-9_]+$\r\n10 中文、英文、数字但不包括下划线等符号:^[\\u4E00-\\u9FA5A-Za-z0-9]+$^[\\u4E00-\\u9FA5A-Za-z0-9]{2,20}$\r\n11 可以输入含有^%&\',;=?$\\\"等字符:[^%&\',;=?$\\x22]+\r\n12 禁止输入含有~的字符:[^~\\x22]+

    三、特殊需求表达式

     1 Email地址:^\\w+([-+.]\\w+)*@\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)*$\r\n 2 域名:[a-zA-Z0-9][-a-zA-Z0-9]{0,62}(/.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})+/.?\r\n 3 InternetURL:[a-zA-z]+://[^\\s]*  ^http://([\\w-]+\\.)+[\\w-]+(/[\\w-./?%&=]*)?$\r\n 4 手机号码:^(13[0-9]|14[0-9]|15[0-9]|16[0-9]|17[0-9]|18[0-9]|19[0-9])\\d{8}$ (由于工信部放号段不定时,所以建议使用泛解析 ^([1][3,4,5,6,7,8,9])\\d{9}$)
    5 电话号码(\"XXX-XXXXXXX\"\"XXXX-XXXXXXXX\"\"XXX-XXXXXXX\"\"XXX-XXXXXXXX\"\"XXXXXXX\"\"XXXXXXXX):^(\\(\\d{3,4}-)|\\d{3.4}-)?\\d{7,8}$ \r\n 6 国内电话号码(0511-4405222021-87888822):\\d{3}-\\d{8}|\\d{4}-\\d{7}
    7
    18位身份证号码(数字、字母x结尾):^((\\d{18})|([0-9x]{18})|([0-9X]{18}))$
    8 帐号是否合法(字母开头,允许5-16字节,允许字母数字下划线):^[a-zA-Z][a-zA-Z0-9_]{4,15}$\r\n 9 密码(以字母开头,长度在6~18之间,只能包含字母、数字和下划线):^[a-zA-Z]\\w{5,17}$\r\n10 强密码(必须包含大小写字母和数字的组合,不能使用特殊字符,长度在8-10之间):^(?=.*\\d)(?=.*[a-z])(?=.*[A-Z]).{8,10}$ \r\n11 日期格式:^\\d{4}-\\d{1,2}-\\d{1,2}\r\n12 一年的12个月(01~09和1~12):^(0?[1-9]|1[0-2])$\r\n13 一个月的31天(01~09和1~31):^((0?[1-9])|((1|2)[0-9])|30|31)$ \r\n14 钱的输入格式:\r\n15 1.有四种钱的表示形式我们可以接受:\"10000.00\"\"10,000.00\", 和没有 \"\"\"10000\"\"10,000\"^[1-9][0-9]*$ \r\n16 2.这表示任意一个不以0开头的数字,但是,这也意味着一个字符\"0\"不通过,所以我们采用下面的形式:^(0|[1-9][0-9]*)$ \r\n17 3.一个0或者一个不以0开头的数字.我们还可以允许开头有一个负号:^(0|-?[1-9][0-9]*)$ \r\n18 4.这表示一个0或者一个可能为负的开头不为0的数字.让用户以0开头好了.把负号的也去掉,因为钱总不能是负的吧.下面我们要加的是说明可能的小数部分:^[0-9]+(.[0-9]+)?$ \r\n19 5.必须说明的是,小数点后面至少应该有1位数,所以\"10.\"是不通过的,但是 \"10\"\"10.2\" 是通过的:^[0-9]+(.[0-9]{2})?$ \r\n20 6.这样我们规定小数点后面必须有两位,如果你认为太苛刻了,可以这样:^[0-9]+(.[0-9]{1,2})?$ \r\n21 7.这样就允许用户只写一位小数.下面我们该考虑数字中的逗号了,我们可以这样:^[0-9]{1,3}(,[0-9]{3})*(.[0-9]{1,2})?$ \r\n22 8.1到3个数字,后面跟着任意个 逗号+3个数字,逗号成为可选,而不是必须:^([0-9]+|[0-9]{1,3}(,[0-9]{3})*)(.[0-9]{1,2})?$ \r\n23 备注:这就是最终结果了,别忘了\"+\"可以用\"*\"替代如果你觉得空字符串也可以接受的话(奇怪,为什么?)最后,别忘了在用函数时去掉去掉那个反斜杠,一般的错误都在这里\r\n24 xml文件:^([a-zA-Z]+-?)+[a-zA-Z0-9]+\\\\.[x|X][m|M][l|L]$\r\n25 中文字符的正则表达式:[\\u4e00-\\u9fa5]\r\n26 双字节字符:[^\\x00-\\xff] (包括汉字在内,可以用来计算字符串的长度(一个双字节字符长度计2,ASCII字符计1))
    27 空白行的正则表达式:\\n\\s*\\r (可以用来删除空白行)\r\n28 HTML标记的正则表达式:<(\\S*?)[^>]*>.*?</\\1>|<.*? /> (网上流传的版本太糟糕,上面这个也仅仅能部分,对于复杂的嵌套标记依旧无能为力)
    29 首尾空白字符的正则表达式:^\\s*|\\s*$或(^\\s*)|(\\s*$) (可以用来删除行首行尾的空白字符(包括空格、制表符、换页符等等),非常有用的表达式)\r\n30 腾讯QQ号:[1-9][0-9]{4,} (腾讯QQ号从10000开始)\r\n31 中国邮政编码:[1-9]\\d{5}(?!\\d) (中国邮政编码为6位数字)\r\n32 IP地址:\\d+\\.\\d+\\.\\d+\\.\\d+ (提取IP地址时有用)
    33 IP地址:((?:(?:25[0-5]|2[0-4]\\\\d|[01]?\\\\d?\\\\d)\\\\.){3}(?:25[0-5]|2[0-4]\\\\d|[01]?\\\\d?\\\\d))    (由@飞龙三少 提供,感谢共享)

    作者:zxin

    出处:http://zxin.cnblogs.com/

    '); +INSERT INTO `ape_document_article` VALUES (87, '

    引言

    客户需求, 需要从docx文档读取内容并且做简单格式化, 难点就在于如何读取docx格式并且转换为php可以识别的字符串形式, 惯例先贴代码.

    代码

    /**\r\n * Class Docx2Text\r\n *\r\n * Docx => String\r\n */\r\nclass Docx2Text\r\n{\r\n    const SEPARATOR_TAB = \"\\t\";\r\n\r\n    /**\r\n     * object zipArchive\r\n     *\r\n     * @var string\r\n     * @access private\r\n     */\r\n    private $docx;\r\n\r\n    /**\r\n     * object domDocument from document.xml\r\n     *\r\n     * @var string\r\n     * @access private\r\n     */\r\n    private $domDocument;\r\n\r\n    /**\r\n     * xml from document.xml\r\n     *\r\n     * @var string\r\n     * @access private\r\n     */\r\n    private $_document;\r\n\r\n    /**\r\n     * xml from numbering.xml\r\n     *\r\n     * @var string\r\n     * @access private\r\n     */\r\n    private $_numbering;\r\n\r\n    /**\r\n     *  xml from footnote\r\n     *\r\n     * @var string\r\n     * @access private\r\n     */\r\n    private $_footnote;\r\n\r\n    /**\r\n     *  xml from endnote\r\n     *\r\n     * @var string\r\n     * @access private\r\n     */\r\n    private $_endnote;\r\n\r\n    /**\r\n     * array of all the endnotes of the document\r\n     *\r\n     * @var string\r\n     * @access private\r\n     */\r\n    private $endnotes;\r\n\r\n    /**\r\n     * array of all the footnotes of the document\r\n     *\r\n     * @var string\r\n     * @access private\r\n     */\r\n    private $footnotes;\r\n\r\n    /**\r\n     * array of all the relations of the document\r\n     *\r\n     * @var string\r\n     * @access private\r\n     */\r\n    private $relations;\r\n\r\n    /**\r\n     * array of characters to insert like a list\r\n     *\r\n     * @var string\r\n     * @access private\r\n     */\r\n    private $numberingList;\r\n\r\n    /**\r\n     * the text content that will be exported\r\n     *\r\n     * @var string\r\n     * @access private\r\n     */\r\n    private $textOuput;\r\n\r\n\r\n    /**\r\n     * boolean variable to know if a chart will be transformed to text\r\n     *\r\n     * @var string\r\n     * @access private\r\n     */\r\n    private $chart2text;\r\n\r\n    /**\r\n     * boolean variable to know if a table will be transformed to text\r\n     *\r\n     * @var string\r\n     * @access private\r\n     */\r\n    private $table2text;\r\n\r\n    /**\r\n     * boolean variable to know if a list will be transformed to text\r\n     *\r\n     * @var string\r\n     * @access private\r\n     */\r\n    private $list2text;\r\n\r\n    /**\r\n     * boolean variable to know if a paragraph will be transformed to text\r\n     *\r\n     * @var string\r\n     * @access private\r\n     */\r\n    private $paragraph2text;\r\n\r\n    /**\r\n     * boolean variable to know if footnotes will be extracteded\r\n     *\r\n     * @var string\r\n     * @access private\r\n     */\r\n    private $footnote2text;\r\n\r\n    /**\r\n     * boolean variable to know if endnotes will be extracted\r\n     *\r\n     * @var string\r\n     * @access private\r\n     */\r\n    private $endnote2text;\r\n\r\n    /**\r\n     * Construct\r\n     *\r\n     * @param $boolTransforms array of boolean values of which elements should be transformed or not\r\n     * @access public\r\n     */\r\n\r\n    public function __construct($boolTransforms = array())\r\n    {\r\n        //table,list, paragraph, footnote, endnote, chart\r\n        if (isset($boolTransforms[\'table\'])) {\r\n            $this->table2text = $boolTransforms[\'table\'];\r\n        } else {\r\n            $this->table2text = true;\r\n        }\r\n\r\n        if (isset($boolTransforms[\'list\'])) {\r\n            $this->list2text = $boolTransforms[\'list\'];\r\n        } else {\r\n            $this->list2text = true;\r\n        }\r\n\r\n        if (isset($boolTransforms[\'paragraph\'])) {\r\n            $this->paragraph2text = $boolTransforms[\'paragraph\'];\r\n        } else {\r\n            $this->paragraph2text = true;\r\n        }\r\n\r\n        if (isset($boolTransforms[\'footnote\'])) {\r\n            $this->footnote2text = $boolTransforms[\'footnote\'];\r\n        } else {\r\n            $this->footnote2text = true;\r\n        }\r\n\r\n        if (isset($boolTransforms[\'endnote\'])) {\r\n            $this->endnote2text = $boolTransforms[\'endnote\'];\r\n        } else {\r\n            $this->endnote2text = true;\r\n        }\r\n\r\n        if (isset($boolTransforms[\'chart\'])) {\r\n            $this->chart2text = $boolTransforms[\'chart\'];\r\n        } else {\r\n            $this->chart2text = true;\r\n        }\r\n\r\n        $this->textOuput = \'\';\r\n        $this->docx = null;\r\n        $this->_numbering = \'\';\r\n        $this->numberingList = array();\r\n        $this->endnotes = array();\r\n        $this->footnotes = array();\r\n        $this->relations = array();\r\n\r\n    }\r\n\r\n    /**\r\n     *\r\n     * Extract the content of a word document and create a text file if the name is given\r\n     *\r\n     * @access public\r\n     * @param string $filename of the word document.\r\n     *\r\n     * @return string\r\n     */\r\n\r\n    public function extract($filename = \'\')\r\n    {\r\n        if (empty($this->_document)) {\r\n            //xml content from document.xml is not got\r\n            exit(\'There is no content\');\r\n        }\r\n\r\n        $this->domDocument = new DomDocument();\r\n        $this->domDocument->loadXML($this->_document);\r\n        //get the body node to check the content from all his children\r\n        $bodyNode = $this->domDocument->getElementsByTagNameNS(\'http://schemas.openxmlformats.org/wordprocessingml/2006/main\', \'body\');\r\n        //We get the body node. it is known that there is only one body tag\r\n        $bodyNode = $bodyNode->item(0);\r\n        foreach ($bodyNode->childNodes as $child) {\r\n            //the children can be a table, a paragraph or a section. We only implement the 2 first option said.\r\n            if ($this->table2text && $child->tagName == \'w:tbl\') {\r\n                //this node is a table and  the content is split with tabs if the variable table2text from the class is true\r\n                $this->textOuput .= $this->table($child) . $this->separator();\r\n            } else {\r\n                //this node is a paragraph\r\n                $this->textOuput .= $this->printWP($child) . ($this->paragraph2text ? $this->separator() : \'\');\r\n            }\r\n        }\r\n        if (!empty($filename)) {\r\n            $this->writeFile($filename, $this->textOuput);\r\n        } else {\r\n            return $this->textOuput;\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Setter\r\n     *\r\n     * @access public\r\n     * @param $filename\r\n     */\r\n    public function setDocx($filename)\r\n    {\r\n        $this->docx = new ZipArchive();\r\n        $ret = $this->docx->open($filename);\r\n        if ($ret === true) {\r\n            $this->_document = $this->docx->getFromName(\'word/document.xml\');\r\n        } else {\r\n            exit(\'failed\');\r\n        }\r\n    }\r\n\r\n    /**\r\n     * extract the content to an array from endnote.xml\r\n     *\r\n     * @access private\r\n     */\r\n    private function loadEndNote()\r\n    {\r\n        if (empty($this->endnotes)) {\r\n            if (empty($this->_endnote)) {\r\n                $this->_endnote = $this->docx->getFromName(\'word/endnotes.xml\');\r\n            }\r\n            if (!empty($this->_endnote)) {\r\n                $domDocument = new DomDocument();\r\n                $domDocument->loadXML($this->_endnote);\r\n                $endnotes = $domDocument->getElementsByTagNameNS(\'http://schemas.openxmlformats.org/wordprocessingml/2006/main\', \'endnote\');\r\n                foreach ($endnotes as $endnote) {\r\n                    $xml = $endnote->ownerDocument->saveXML($endnote);\r\n                    $this->endnotes[$endnote->getAttribute(\'w:id\')] = trim(strip_tags($xml));\r\n                }\r\n            }\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Extract the content to an array from footnote.xml\r\n     *\r\n     * @access private\r\n     */\r\n    private function loadFootNote()\r\n    {\r\n        if (empty($this->footnotes)) {\r\n            if (empty($this->_footnote)) {\r\n                $this->_footnote = $this->docx->getFromName(\'word/footnotes.xml\');\r\n            }\r\n            if (!empty($this->_footnote)) {\r\n                $domDocument = new DomDocument();\r\n                $domDocument->loadXML($this->_footnote);\r\n                $footnotes = $domDocument->getElementsByTagNameNS(\'http://schemas.openxmlformats.org/wordprocessingml/2006/main\', \'footnote\');\r\n                foreach ($footnotes as $footnote) {\r\n                    $xml = $footnote->ownerDocument->saveXML($footnote);\r\n                    $this->footnotes[$footnote->getAttribute(\'w:id\')] = trim(strip_tags($xml));\r\n                }\r\n            }\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Extract the styles of the list to an array\r\n     *\r\n     * @access private\r\n     */\r\n    private function listNumbering()\r\n    {\r\n        $ids = array();\r\n        $nums = array();\r\n        //get the xml code from the zip archive\r\n        $this->_numbering = $this->docx->getFromName(\'word/numbering.xml\');\r\n        if (!empty($this->_numbering)) {\r\n            //we use the domdocument to iterate the children of the numbering tag\r\n            $domDocument = new DomDocument();\r\n            $domDocument->loadXML($this->_numbering);\r\n            $numberings = $domDocument->getElementsByTagNameNS(\'http://schemas.openxmlformats.org/wordprocessingml/2006/main\', \'numbering\');\r\n            //there is only one numbering tag in the numbering.xml\r\n            $numberings = $numberings->item(0);\r\n            foreach ($numberings->childNodes as $child) {\r\n                $flag = true;//boolean variable to know if the node is the first style of the list\r\n                foreach ($child->childNodes as $son) {\r\n                    if ($child->tagName == \'w:abstractNum\' && $son->tagName == \'w:lvl\') {\r\n                        foreach ($son->childNodes as $daughter) {\r\n                            if ($daughter->tagName == \'w:numFmt\' && $flag) {\r\n                                $nums[$child->getAttribute(\'w:abstractNumId\')] = $daughter->getAttribute(\'w:val\');//set the key with internal index for the listand the value it is the type of bullet\r\n                                $flag = false;\r\n                            }\r\n                        }\r\n                    } elseif ($child->tagName == \'w:num\' && $son->tagName == \'w:abstractNumId\') {\r\n                        $ids[$son->getAttribute(\'w:val\')] = $child->getAttribute(\'w:numId\');//$ids is the index of the list\r\n                    }\r\n                }\r\n            }\r\n            //once we know what kind of list there is in the documents, is prepared the bullet that the library will use\r\n            foreach ($ids as $ind => $id) {\r\n                if ($nums[$ind] == \'decimal\') {\r\n                    //if the type is decimal it means that the bullet will be numbers\r\n                    $this->numberingList[$id][0] = range(1, 10);\r\n                    $this->numberingList[$id][1] = range(1, 10);\r\n                    $this->numberingList[$id][2] = range(1, 10);\r\n                    $this->numberingList[$id][3] = range(1, 10);\r\n                } else {\r\n                    //otherwise is *, and other characters\r\n                    $this->numberingList[$id][0] = array(\'*\', \'*\', \'*\', \'*\', \'*\', \'*\', \'*\', \'*\', \'*\', \'*\', \'*\', \'*\', \'*\', \'*\', \'*\', \'*\', \'*\');\r\n                    $this->numberingList[$id][1] = array(chr(175), chr(175), chr(175), chr(175), chr(175), chr(175), chr(175), chr(175), chr(175), chr(175), chr(175), chr(175));\r\n                    $this->numberingList[$id][2] = array(chr(237), chr(237), chr(237), chr(237), chr(237), chr(237), chr(237), chr(237), chr(237), chr(237), chr(237), chr(237));\r\n                    $this->numberingList[$id][3] = array(chr(248), chr(248), chr(248), chr(248), chr(248), chr(248), chr(248), chr(248), chr(248), chr(248), chr(248));\r\n                }\r\n            }\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Extract the content of a w:p tag\r\n     *\r\n     * @access private\r\n     * @param $node object\r\n     * @return string\r\n     */\r\n    private function printWP($node)\r\n    {\r\n        $ilvl = $numId = -1;\r\n        if ($this->list2text) {//transform the list in ooxml to formatted list with tabs and bullets\r\n            if (empty($this->numberingList)) {//check if numbering.xml is extracted from the zip archive\r\n                $this->listNumbering();\r\n            }\r\n            //use the xpath to get expecific children from a node\r\n            $xpath = new DOMXPath($this->domDocument);\r\n            $query = \'w:pPr/w:numPr\';\r\n            $xmlLists = $xpath->query($query, $node);\r\n            $xmlLists = $xmlLists->item(0);\r\n\r\n            //if ($xmlLists->tagName == \'w:numPr\') {\r\n            //    if ($xmlLists->hasChildNodes()) {\r\n            //        foreach ($xmlLists->childNodes as $child) {\r\n            //            if ($child->tagName == \'w:ilvl\') {\r\n            //                $ilvl = $child->getAttribute(\'w:val\');\r\n            //            }elseif ($child->tagName == \'w:numId\') {\r\n            //                $numId = $child->getAttribute(\'w:val\');\r\n            //            }\r\n            //        }\r\n            //    }\r\n            //}\r\n            //if (($ilvl != -1) && ($numId != -1)) {\r\n            //    //if is founded the style index of the list in the document and the kind of list\r\n            //    $ret = \'\';\r\n            //    for($i=-1; $i < $ilvl; $i++) {\r\n            //        if(self::DEBUG) {\r\n            //            $ret .= self::SEPARATOR_TAB_DEBUG;\r\n            //        }\r\n            //        else {\r\n            //            $ret .= self::SEPARATOR_TAB;\r\n            //        }\r\n            //    }\r\n            //    $ret .= array_shift($this->numberingList[$numId][$ilvl]) . \' \' . $this->toText($node);  //print the bullet\r\n            //} else {\r\n            $ret = $this->toText($node);\r\n            //}\r\n        } else {\r\n            //if dont want to formatted lists, we strip from html tags\r\n            $ret = $this->toText($node);\r\n        }\r\n\r\n\r\n        //get the data from the charts\r\n        if ($this->chart2text) {\r\n            $query = \'w:r/w:drawing/wp:inline\';\r\n            $xmlChart = $xpath->query($query, $node);\r\n            //get the relation id from the document, to get the name of the xml chart file from the relations to extract the xml code.\r\n            foreach ($xmlChart as $chart) {\r\n                foreach ($chart->childNodes as $child) {\r\n                    foreach ($child->childNodes as $child2) {\r\n                        foreach ($child2->childNodes as $child3) {\r\n                            $rid = $child3->getAttribute(\'r:id\');\r\n                        }\r\n                    }\r\n                }\r\n            }\r\n            //if (!empty($rid)) {\r\n            //    if (empty($this->relations)) {\r\n            //        $this->loadRelations();\r\n            //    }\r\n            //    //get the name of the chart xml file from the relations docuemnt\r\n            //    $dataChart = new getDataFromXmlChart($this->docx->getFromName(\'word/\' . $this->relations[$rid][\'file\']));\r\n            //    if (in_array($this->chart2text, array(2, \'table\'))) {\r\n            //        $ret .= $this->printChartDataTable($dataChart);//formatted print of the chart data\r\n            //    } else {\r\n            //        $ret .= $this->printChartDataArray($dataChart);//formatted print of the chart data\r\n            //    }\r\n            //}\r\n        }\r\n        //extract the expecific endnote to insert with the text content\r\n        if ($this->endnote2text) {\r\n            if (empty($this->endnotes)) {\r\n                $this->loadEndNote();\r\n            }\r\n            $query = \'w:r/w:endnoteReference\';\r\n            $xmlEndNote = $xpath->query($query, $node);\r\n            foreach ($xmlEndNote as $note) {\r\n                $ret .= \'[\' . $this->endnotes[$note->getAttribute(\'w:id\')] . \'] \';\r\n            }\r\n        }\r\n        //extract the expecific footnote to insert with the text content\r\n        if ($this->footnote2text) {\r\n            if (empty($this->footnotes)) {\r\n                $this->loadFootNote();\r\n            }\r\n            $query = \'w:r/w:footnoteReference\';\r\n            $xmlFootNote = $xpath->query($query, $node);\r\n            foreach ($xmlFootNote as $note) {\r\n                $ret .= \'[\' . $this->footnotes[$note->getAttribute(\'w:id\')] . \'] \';\r\n            }\r\n        }\r\n        if ((($ilvl != -1) && ($numId != -1)) || (1)) {\r\n            $ret .= $this->separator();\r\n        }\r\n\r\n        return $ret;\r\n    }\r\n\r\n    /**\r\n     * return a text end of line\r\n     *\r\n     * @access private\r\n     */\r\n    private function separator()\r\n    {\r\n        return \"\\r\\n\";\r\n    }\r\n\r\n    /**\r\n     *\r\n     * Extract the content of a table node from the document.xml and return a text content\r\n     *\r\n     * @access private\r\n     * @param $node object\r\n     *\r\n     * @return string\r\n     */\r\n    private function table($node)\r\n    {\r\n        $output = \'\';\r\n        if ($node->hasChildNodes()) {\r\n            foreach ($node->childNodes as $child) {\r\n                //start a new line of the table\r\n                if ($child->tagName == \'w:tr\') {\r\n                    foreach ($child->childNodes as $cell) {\r\n                        //start a new cell\r\n                        if ($cell->tagName == \'w:tc\') {\r\n                            if ($cell->hasChildNodes()) {\r\n                                //\r\n                                foreach ($cell->childNodes as $p) {\r\n                                    $output .= $this->printWP($p);\r\n                                }\r\n                                $output .= self::SEPARATOR_TAB;\r\n                            }\r\n                        }\r\n                    }\r\n                }\r\n                $output .= $this->separator();\r\n            }\r\n        }\r\n        return $output;\r\n    }\r\n\r\n\r\n    /**\r\n     *\r\n     * Extract the content of a node from the document.xml and return only the text content and. stripping the html tags\r\n     *\r\n     * @access private\r\n     * @param $node object\r\n     *\r\n     * @return string\r\n     */\r\n    private function toText($node)\r\n    {\r\n        $xml = $node->ownerDocument->saveXML($node);\r\n        return trim(strip_tags($xml));\r\n    }\r\n}\r\n\r\n// 实例化\r\n$text = new Docx2Text();\r\n// 加载docx文件\r\n$text->setDocx(\'./1.docx\');\r\n// 将内容存入$docx变量中\r\n$docx = $text->extract();\r\n// 调试输出\r\nvar_dump($docx);\r\n

    小结

    代码中处理docx的类来自这里
    其实docx就是xml的一种扩展类型的文档.

    转载自  https://blog.csdn.net/hldh214/article/details/51549866

    '); +INSERT INTO `ape_document_article` VALUES (88, '

    jquery.confirm 和 modal 弹窗同时打开的bug 会导致 confirm里的 input不可以输入,解决办法,modal窗隐藏或者选择别的插件替代

    还有中解决办法  据说是外层的 tabindex导致的,但是我尝试打开弹窗时候移除没有效果,所以放弃

    '); +INSERT INTO `ape_document_article` VALUES (89, '

    可修改源码,将其配置为一个参数,存在的时候才加入input元素的webkitdirectory属性

    创建元素对象添加上

    以下是源码中修改内容

    菜鸟个人办法


    转载自知乎  pzma

    '); +INSERT INTO `ape_document_article` VALUES (90, '

    首先

     composer require phpoffice/phpspreadsheet

    然后上代码

    配合数据库切片效果更好,但是为了简单方便就直接。。。。

    getActiveSheet();\r\n\r\n        //设置列\r\n        $rowAr=self::setRowAr($count);\r\n        foreach ($rowAr as $k => $v) {\r\n            if($k>$count) break;\r\n            $sheet->setCellValue($v.\'1\',$titles[$k]);\r\n        }\r\n\r\n        //写入值\r\n        foreach ($datas as $k => $v) {\r\n            foreach ($rowAr as $ke => $ve){\r\n                if($ke>$count) break;\r\n                $sheet->setCellValue($ve.($k+2),$v[$fields[$ke]]);\r\n                $spreadsheet->getActiveSheet()->getColumnDimension($ve)->setWidth(10); //固定列宽\r\n            }\r\n        }\r\n        //冻结首行\r\n        $spreadsheet->getActiveSheet()->freezePaneByColumnAndRow(0,2);\r\n\r\n        //在输出Excel前,缓冲区中处理BOM头\r\n        ob_end_clean();\r\n        ob_start();\r\n\r\n        $fileNameArr = explode(\'.\',$file_name);\r\n        $ext = array_pop($fileNameArr);\r\n        header(\'Content-Type: application/vnd.ms-excel\');\r\n        header(\"Content-Disposition: attachment;filename=$file_name\");\r\n        header(\'Cache-Control: max-age=0\');\r\n        $objWriter = IOFactory::createWriter($spreadsheet, ucfirst($ext));//把后缀名首字母大写\r\n        $objWriter->save(\'php://output\');\r\n        //删除清空:\r\n        $spreadsheet->disconnectWorksheets();\r\n        unset($spreadsheet);\r\n        return true;\r\n    }\r\n\r\n    /**\r\n     * 设置列一维数组(最多701列)\r\n     * @param int $count\r\n     * @return false|string[]\r\n     * @date 2020-12-11 17:32\r\n     */\r\n    public function setRowAr($count=26){\r\n        $indData=\'A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z\';\r\n        $indData=explode(\',\',$indData);\r\n        $curCount=26;\r\n        for ($i=0; $i <26 ; $i++) {\r\n            for ($j=0; $j <26 ; $j++) {\r\n                if($curCount>=$count) return $indData;\r\n                $indData[]=$indData[$i].$indData[$j];\r\n                $curCount++;\r\n            }\r\n        }\r\n        return $indData;\r\n    }\r\n}
    '); +INSERT INTO `ape_document_article` VALUES (91, '

    在最近的后台生成代码中发现 js动态的生成html 和 直接复制粘贴的样式不一致

    模板使用的是 Light-Year-Admin-Template 

    js生成代码为  

    <span data-value=\"2020/11/30-2020/12/06\" class=\"label label-success\">2020/11/30-2020/12/06&nbsp;&nbsp;<a href=\"#\" class=\"remove-choose\" title=\"移除\">x</a></span><span data-value=\"2020/11/30-2020/12/06\" class=\"label label-success\">2020/11/30-2020/12/06&nbsp;&nbsp;<a href=\"#\" class=\"remove-choose\" title=\"移除\">x</a></span><span data-value=\"2020/11/30-2020/12/06\" class=\"label label-success\">2020/11/30-2020/12/06&nbsp;&nbsp;<a href=\"#\" class=\"remove-choose\" title=\"移除\">x</a></span>

    原生html

    <span data-value=\"2020/11/30-2020/12/06\" class=\"label label-success\">2020/11/30-2020/12/06&nbsp;&nbsp;<a href=\"#\" class=\"remove-choose\" title=\"移除\">x</a></span>\r\n<span data-value=\"2020/11/30-2020/12/06\" class=\"label label-success\">2020/11/30-2020/12/06&nbsp;&nbsp;<a href=\"#\" class=\"remove-choose\" title=\"移除\">x</a></span>\r\n\r\n<span data-value=\"2020/11/30-2020/12/06\" class=\"label label-success\">2020/11/30-2020/12/06&nbsp;&nbsp;<a href=\"#\" class=\"remove-choose\" title=\"移除\">x</a></span>

    对比发现代码是一样的唯一的区别就是 换行的问题 解决思路在动态生成代码后面 加 \'/n\'

    所以修改代码

    let html = \'\\n\'+\r\n        \"<span data-value=\\\"\"+time_select+\"\\\" class=\\\"label label-success\\\">\"+time_select+\"&nbsp;&nbsp;<a href=\\\"#\\\" class=\\\"remove-choose\\\" title=\\\"移除\\\">x</a></span> \\n\";\r\n$(this).closest(\'.searchForm\').find(\'.time-box\').append(html);

    至此问题解决

    注意 appendTo 写法无效,改为append 即可

    '); +INSERT INTO `ape_document_article` VALUES (92, '

    解决完样式

    \"微信图片_20201215140143.png\"


    代码

    .time-box .label{\r\n  display:inline-block;}
    '); +INSERT INTO `ape_document_article` VALUES (93, '

    html 代码 ,注意这里要使用id,否则可能会出现销毁无效的问题

    id=\"tree-table\">

    js代码

    let columns;  //栏目\r\ncolumns = [\r\n   {\r\n	field: \'name\',\r\n	title: \'\'\r\n  },\r\n {\r\n	field: \'name\',\r\n	title: \'\'\r\n  },\r\n {\r\n	field: \'name\',\r\n	title: \'\'\r\n  },\r\n\r\n {\r\n	field: \'name\',\r\n	title: \'\'\r\n  }\r\n];\r\n//定义表格let $treeTable =  $(\'#tree-table\');\r\n//判断是否显示,显示则需要销毁重新渲染\r\n$treeTable.bootstrapTable(\'destroy\');\r\n//表格渲染\r\n$treeTable.bootstrapTable({\r\n  data:data,\r\n  columns :columns \r\n.....\r\n})

    这样即可

    '); +INSERT INTO `ape_document_article` VALUES (94, '

    方法1:

    浏览器自带的一个方法

    const num=12345.6789\r\n \r\nnum.toLocaleString();//=>\"12,345.679\"

    方法2:

    正则匹配

    function format (num) {\r\n \r\n    return (num+ \'\').replace(/(\\d{1,3})(?=(\\d{3})+(?:$|\\.))/g,\'$1,\');\r\n \r\n}
    '); +INSERT INTO `ape_document_article` VALUES (95, '

    更新列的数据

    let rows = {\r\n	index : index, //更新列所在行的索引\r\n	field : \"collection_status\", //要更新列的field\r\n	value : 1 //要更新列的数据\r\n}\r\n//更新表格数据\r\n$(\"#tb_departments\").bootstrapTable(\"updateCell\",rows);

    获取列数据

    let allTableData = $(\'#tb_departments\').bootstrapTable(\'getData\');

    获取选中数据

    let selectedItem = $(\'#tb_departments\').bootstrapTable(\'getAllSelections\');
    '); +INSERT INTO `ape_document_article` VALUES (96, '
    var tool = function(){\r\n    //设置缓存\r\n    function setCache(name, value) {\r\n        var storage = \'localStorage\';\r\n        if(!window.localStorage){\r\n            storage =  \'cookie\';\r\n        }\r\n        if (settings === null) {\r\n            \'localStorage\' == storage ?  window.localStorage.removeItem(name): delCookie(name);\r\n        } else {\r\n            \'localStorage\' == storage ?  window.localStorage.setItem(name,settings): addCookie(name,settings);\r\n        }\r\n\r\n    }\r\n\r\n    //清空缓存\r\n    function clearCache(name) {\r\n        var storage = \'localStorage\';\r\n        if(!window.localStorage){\r\n            storage =  \'cookie\';\r\n        }\r\n        if (name === null) {\r\n            \'localStorage\' == storage ?  window.localStorage.clear(): clearAllCookie();\r\n        } else {\r\n            \'localStorage\' == storage ?  window.localStorage.removeItem(name): delCookie(name);\r\n        }\r\n        return true;\r\n    }\r\n\r\n    //删除所有cookie\r\n    function clearAllCookie() {\r\n        var keys = document.cookie.match(/[^ =;]+(?=\\=)/g);\r\n        if(keys) {\r\n            for(var i = keys.length; i--;)\r\n                document.cookie = keys[i] + \'=0;expires=\' + new Date(0).toUTCString()\r\n        }\r\n        return true;\r\n    }\r\n\r\n\r\n    //提取缓存\r\n    function getCache(name) {\r\n        var data =  storage == \'localStorage\'?  window.localStorage.getItem(name): $.cookie.get(name);\r\n        if (typeof data == \'string\') {\r\n            try {\r\n                var obj=JSON.parse(data);\r\n                if(typeof data == \'object\' && data ){\r\n                    data = obj;\r\n                }\r\n            } catch(e) {\r\n                ///\r\n            }\r\n        }\r\n        return data;\r\n    }\r\n\r\n    /**\r\n     * 添加cookie\r\n     * @param objName\r\n     * @param objValue\r\n     * @param objHours\r\n     */\r\n    function addCookie(objName, objValue, objHours){//添加cookie\r\n        var str = objName + \"=\" + escape(objValue);\r\n        if (objHours > 0) {//为0时不设定过期时间,浏览器关闭时cookie自动消失\r\n            var date = new Date();\r\n            var ms = objHours * 3600 * 1000;\r\n            date.setTime(date.getTime() + ms);\r\n            str += \"; expires=\" + date.toGMTString();\r\n        }\r\n        document.cookie = str;\r\n        return true;\r\n    }\r\n\r\n    /**\r\n     * 获取cookie\r\n     * @param objName\r\n     * @returns {string}\r\n     */\r\n    function getCookie(objName){//获取指定名称的cookie的值\r\n        var arrStr = document.cookie.split(\"; \");\r\n        for (var i = 0; i < arrStr.length; i++) {\r\n            var temp = arrStr[i].split(\"=\");\r\n            if (temp[0] == objName)\r\n                return unescape(temp[1]);\r\n        }\r\n    }\r\n\r\n    /**\r\n     * 移除cookie\r\n     * @param name\r\n     */\r\n    function delCookie(name){//为了删除指定名称的cookie,可以将其过期时间设定为一个过去的时间\r\n        var date = new Date();\r\n        date.setTime(date.getTime() - 10000);\r\n        document.cookie = name + \"=a; expires=\" + date.toGMTString();\r\n    }\r\n\r\n    //cache 方法 包含设置 删除 获取\r\n    function cache(name, settings,) {\r\n        name = name || \'cache\';\r\n        var storage = \'localStorage\';\r\n        if(!window.localStorage){\r\n            storage =  \'cookie\';\r\n        }\r\n\r\n        //先判断是不是删除\r\n        if(settings === null){\r\n            //删除缓存\r\n            storage == \'localStorage\'?  window.localStorage.removeItem(name): delCookie(name);\r\n        }\r\n        //判断是不是获取\r\n        if(!settings){\r\n            //获取缓存\r\n            var data =  storage == \'localStorage\'?  window.localStorage.getItem(name): getCookie(name);\r\n            if (typeof data == \'string\') {\r\n                try {\r\n                    var obj=JSON.parse(data);\r\n                    if(typeof data == \'object\' && data ){\r\n                        data = obj;\r\n                    }\r\n                } catch(e) {\r\n                    ///\r\n                }\r\n            }\r\n            return data;\r\n        }\r\n        settings = typeof settings ===\"object\" ?JSON.stringify(settings):settings;\r\n        //开始写缓存\r\n        storage == \'localStorage\'?  window.localStorage.setItem(name,settings): addCookie(name,settings);\r\n        return true;\r\n    }\r\n\r\n    return {\r\n        // 页面加载动画\r\n        setCache : function (name, value) {\r\n            setCache(name, value)\r\n        },\r\n        getCache :function (name) {\r\n            getCache(name)\r\n        },\r\n        cache: function (name, settings){\r\n            return cache(name, settings);\r\n        }\r\n    };\r\n}();
    '); +INSERT INTO `ape_document_article` VALUES (97, '

    php版本结巴分词仓库 jieba分词

    介绍

    支持三種分詞模式:\r\n1)默認精確模式,試圖將句子最精確地切開,適合文本分析;\r\n2)全模式,把句子中所有的可以成詞的詞語都掃描出來,但是不能解決歧義。(需要充足的字典)\r\n搜尋引擎模式,在精確模式的基礎上,對長詞再次切分,提高召回率,適合用於搜尋引擎分詞。\r\n支持繁體斷詞\r\n支持自定義詞典

    使用

    自動安裝:使用 composer 安裝後,透過 autoload 引用

    composer require fukuball/jieba-php:dev-master
    require_once \"/path/to/your/vendor/multi-array/MultiArray.php\";\r\nrequire_once \"/path/to/your/vendor/multi-array/Factory/MultiArrayFactory.php\";\r\nrequire_once \"/path/to/your/class/Jieba.php\";\r\nrequire_once \"/path/to/your/class/Finalseg.php\";


    使用

    use Fukuball\\Jieba\\Jieba;\r\nuse Fukuball\\Jieba\\Finalseg;\r\n\r\n\r\nJieba::init();\r\nFinalseg::init();\r\n\r\n$seg_list = Jieba::cut(\"怜香惜玉也得要看对象啊!\");\r\nvar_dump($seg_list);\r\n\r\n$seg_list = Jieba::cut(\"我来到北京清华大学\", true);\r\nvar_dump($seg_list); #全模式\r\n\r\n$seg_list = Jieba::cut(\"我来到北京清华大学\", false);\r\nvar_dump($seg_list); #默認精確模式\r\n\r\n$seg_list = Jieba::cut(\"他来到了网易杭研大厦\");\r\nvar_dump($seg_list);\r\n\r\n$seg_list = Jieba::cutForSearch(\"小明硕士毕业于中国科学院计算所,后在日本京都大学深造\"); #搜索引擎模式\r\nvar_dump($seg_list);


    功能

    Jieba::cut(\"怜香惜玉也得要看对象啊!\");\r\n\r\nJieba::cutForSearch(\"小明硕士毕业于中国科学院计算所,后在日本京都大学深造\"); #搜索引擎模式
     Jieba::loadUserDict(file_name) # file_name 为自定义词典的绝对路径
    JiebaAnalyse::extractTags($content, $top_k)\r\ncontent 为待提取的文本\r\ntop_k 为返回几个 TF/IDF 权重最大的关键词,默认值 20\r\n可使用 setStopWords 增加自定义 stop words
    Posseg::cut(\"这是一个伸手不见五指的黑夜。我叫孙悟空,我爱北京,我爱Python和C++。\")
    Jieba::init(array(\'mode\'=>\'default\',\'dict\'=>\'big\'));\r\nFinalseg::init();\r\n\r\n$seg_list = Jieba::cut(\"怜香惜玉也得要看对象啊!\");
    Jieba::init(array(\'cjk\'=>\'all\'));\r\nFinalseg::init();\r\n\r\n$seg_list = Jieba::cut(\"한국어 또는 조선말은 제주특별자치도를 제외한 한반도 및 그 부속 도서와 한민족 거주 지역에서 쓰이는 언어로\");
    Jieba::init(array(\'mode\'=>\'test\',\'dict\'=>\'big\'));\r\nFinalseg::init();\r\n\r\n$seg_list = Jieba::tokenize(\"永和服装饰品有限公司\");
    '); +INSERT INTO `ape_document_article` VALUES (98, '
    {{jobInfo.company_name|selection}}\r\n\r\nfilters:{\r\n    //隐藏隐私信息的方法\r\n    selection(value){\r\n	    if(that.userId){\r\n	        return value;\r\n	    }else{\r\n	     return \'XXXXXXXXX\';\r\n	    }\r\n    },\r\n}     \r\n\r\n.selection {\r\n    -moz-user-select: -moz-none;\r\n	-moz-user-select: none;\r\n	-o-user-select:none;\r\n	-khtml-user-select:none;\r\n	-webkit-user-select:none;\r\n	-ms-user-select:none;\r\n	user-select:none;\r\n	color: transparent !important;\r\n	text-shadow: 0px 0px 15px #666 !important;\r\n}
    '); +INSERT INTO `ape_document_article` VALUES (99, '
    amd audio coprocessor这个驱动能用就别更新,而且要记得备份驱动小新 13proAMD 锐龙4600U版本更新amd audio coprocessor这个驱动,瞬间就关机很慢,开机也很慢,在启动那个界面滚动好几分钟才进入系统,我以为电脑挂了呢。 到联想电脑管家恢复上一个驱动就恢复正常了。至少2.89.0.61这个版本千万别更新。


    解决办法  到设备管理器(此电脑-右键),系统设备里面找到 amd audio coprocessor,选择回退就可以了。



    来自联想论坛  Water2302

    '); +INSERT INTO `ape_document_article` VALUES (100, '


    '); +INSERT INTO `ape_document_article` VALUES (101, '

    测试是否启动成功简介

    来自百度百科:
    ElasticSearch是一个基于Lucene的搜索服务器。它提供了一个分布式多用户能力的全文搜索引擎,基于RESTful web接口。Elasticsearch是用Java语言开发的,并作为Apache许可条款下的开放源码发布,是一种流行的企业级搜索引擎。ElasticSearch用于云计算中,能够达到实时搜索,稳定,可靠,快速,安装使用方便。

    二、elasticsearch下载及安装

    1. 安装jdk

    ES 7.8 需要 java 11 环境,centos 默认自带是openjdk1.8或者没有

    java -version

    如果出现以下界面则说明存在,需要升级\"微信图片_20210130235038.png\"

    rpm -qa | grep jdk ##查找安装的jdk\r\n\r\nrpm -e --nodeps java-1.8.0-openjdk-1.8.0.275.b01-1.el8_3.x86_64 #删除安装的jdk\r\nrpm -e --nodeps java-1.8.0-openjdk-headless-1.8.0.275.b01-1.el8_3.x86_64\r\n

    如果提示,下面代码则表示不存在跳过下面的步骤

    bash: /usr/bin/java: No such file or directory

    执行安装jdk11

     yum install java-11-openjdk* -y

    2. 下载、传输并解压es

    1. es 地址 ,选择修新版的地址
    2.  wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-7.10.2-linux-x86_64.tar.gz
    3. 解压下载后的安装包。
    4. tar xzvf elasticsearch-7.10.2-linux-x86_64.tar.gz
    5. 解压完成后进入到bin文件夹下,并启动elasticsearch。
    6. cd /usr/local/elasticsearch-7.10.2-linux-x86_64.tar.gz/bin/\r\nsu es                        # 使用创建的账户进行启动\r\n./elasticsearch     # 启动elasticsearch
    7. 测试是否启动成功
    8. curl 127.0.0.1:9200\r\n

    \"微信图片_20210131000452.png\"

    可能会出现以下错误

    可能会出现以下错误

    1)jdk版本不对应

    \"启动报错\"

    解决:参照安装jdk重新安装jdk

    2)root账户不能启动

    \"微信图片_20210131000904.png\"

    解决

    # 创建es账户\r\nadduser es\r\n# 修改密码\r\npasswd es  \r\n#输入的密码会提示不能少于8个字符,并且不能太过简单(eg:123qwe.lxw)\r\n#给es用户elasticsearch目录的授权\r\nchown -R es /usr/local/elasticsearch-7.4.2/
    '); +INSERT INTO `ape_document_article` VALUES (102, '

    首先要安装驱动,官方的辣鸡服务支持别指望了 2k/s  哎!!

    苹果官网驱动

    https://support.apple.com/kb/DL1888?viewlocale=zh_CN&locale=zh_CN

    一路安装到底

    然后进入系统偏好设置-打印机与扫描仪

    \"1612188891236.jpg\"

    左下角点击+号已经识别到打印机了

    \"1612189484604.jpg\"\"1612189517494.jpg\"

    选择软件(也就是驱动)搜索HP DeskJet 21 选择hp deskjet 2000 j200 series驱动

    \"1612189883590.jpg\"

    添加hp deskjet 2000 j200 series后,用hp deskjet 2000 j200 series测试打印,然后你就可以享受你的打印机了(mac)

    惠普的命名很迷,其实用虚拟机也能打(Windows驱动方便太多)。

    '); +INSERT INTO `ape_document_article` VALUES (103, '

    效果:

    \"20180420095622973.png\"

    <!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title></title>\r\n</head>\r\n<body>\r\n<div>\r\n    <div style=\"float: left;\">\r\n        时间周期\r\n        <select id=\"changeMonthOrWeek\" name=\"changeMonthOrWeek\" class=\"\" style=\"padding-left: 10px; \">\r\n            <option value=\"1\">月</option>\r\n            <option value=\"2\">周</option>\r\n        </select>:\r\n        <select id=\"startYear\" class=\"year-crm\"></select>\r\n        <select id=\"startMonth\" class=\" month-crm\"></select>\r\n    </div>\r\n    <div id=\"changeMonthDiv\" style=\"float: left;\">\r\n        <span style=\"padding: 0px 10px\">至</span>\r\n        <select id=\"endYear\" class=\"year-crm\"></select>\r\n        <select id=\"endMonth\" class=\"month-crm\"></select>\r\n    </div>\r\n    <div id=\"changeWeekDiv\" style=\"display: none;\">\r\n        <select id=\"startEndDay\" class=\"week-crm\"></select>\r\n    </div>\r\n</div>\r\n</body>\r\n<script src=\"js/jquery.min.js\"></script>\r\n<script>\r\n    //展示周\r\n    function weekShow(id,df,dv) {\r\n        $(id).html(\"\");\r\n        $(id).append(\"<option value=\'\'>--------------周--------------</option>\");\r\n        if(df){\r\n            var data = weekCount(dv)\r\n            for(var i =0;i<data.length;i++){\r\n                var v = data[i].timesStart+\"~\"+data[i].timesEnd;\r\n                $(id).append(\"<option value=\'\"+v+\"\'>\"+v+\"</option>\");\r\n            }\r\n        }\r\n    }\r\n    weekShow(\"#startEndDay\",true);\r\n    $(\"#changeMonthOrWeek\").change(function () {\r\n       var val = this.value;\r\n       if(val==1){\r\n           $(\"#changeWeekDiv\").hide();\r\n           $(\"#changeMonthDiv\").show();\r\n           monthShow(\".month-crm\");\r\n           yearsShow(\".year-crm\",2014);\r\n       }\r\n        if(val==2){\r\n            $(\"#changeWeekDiv\").show();\r\n            $(\"#changeMonthDiv\").hide();\r\n            monthShow(\"#startMonth\");\r\n            yearsShow(\"#startYear\",2014);\r\n            weekShow(\"#startEndDay\");\r\n        }\r\n    });\r\n    //周视图改变的时候\r\n    $(\"#startYear\").change(function () {\r\n        var val = $(\"#changeMonthOrWeek\").val();\r\n        var startMonth = $(\"#startMonth\").val();\r\n        if(val==2&&startMonth!=\"\"){\r\n            weekShow(\"#startEndDay\",true,this.value+\"-\"+startMonth);\r\n        }\r\n    });\r\n    //周视图改变的时候\r\n    $(\"#startMonth\").change(function () {\r\n        var val = $(\"#changeMonthOrWeek\").val();\r\n        var startYear = $(\"#startYear\").val();\r\n        if(val==2&&startYear!=\"\"){\r\n            weekShow(\"#startEndDay\",true,startYear+\"-\"+this.value);\r\n        }\r\n    });\r\n    //一个月的周区间\r\n    function weekCount(df) {\r\n        var date=new Date;\r\n        if(df){\r\n            date = new Date(df);\r\n        }\r\n        var dateTemp = date;\r\n        dateTemp.setDate(1);\r\n        var intWeek = dateTemp.getDay();\r\n        var dateStartDay,dateEndDay;\r\n        var lastDay = new Date(date.getFullYear(), date.getMonth() + 1, 0);\r\n        // console.log(lastDay)\r\n        var timesStart,timesEnd;\r\n        var arr = [];\r\n        dateStartDay = new Date(dateTemp);\r\n        dateStartDay.setDate(dateStartDay.getDate()-(intWeek-1==-1?6:intWeek-1));\r\n        timesStart = dateStartDay.getFullYear()+\"-\"+dateToolAddZero(dateStartDay.getMonth()+1)+\"-\"+dateToolAddZero(dateStartDay.getDate());\r\n        dateEndDay = new Date(timesStart);\r\n        dateEndDay.setDate(dateEndDay.getDate()+6);\r\n        timesEnd = dateEndDay.getFullYear()+\"-\"+dateToolAddZero(dateEndDay.getMonth()+1)+\"-\"+dateToolAddZero(dateEndDay.getDate());\r\n        arr.push({\"timesStart\":timesStart,\"timesEnd\":timesEnd});\r\n        var loop = true;\r\n        var index = 1;\r\n        while (loop){\r\n            var dateStartDay2 = new Date(timesEnd);\r\n            dateStartDay2.setDate(dateStartDay2.getDate()+1);\r\n            var timesStart = dateStartDay2.getFullYear()+\"-\"+dateToolAddZero(dateStartDay2.getMonth()+1)+\"-\"+dateToolAddZero(dateStartDay2.getDate());\r\n            var dateEndDay2 = new Date(timesStart);\r\n            dateEndDay2.setDate(dateEndDay2.getDate()+6);\r\n            timesEnd = dateEndDay2.getFullYear()+\"-\"+dateToolAddZero(dateEndDay2.getMonth()+1)+\"-\"+dateToolAddZero(dateEndDay2.getDate());\r\n            if(lastDay.getDay()==0){\r\n                var tempDate = new Date(timesEnd);\r\n                tempDate = new Date(dateStartDay2.getFullYear(), dateStartDay2.getMonth());\r\n                if(tempDate>=lastDay){\r\n                    loop=false;\r\n                    break;\r\n                }\r\n            }else {\r\n                var tempDate = new Date(timesEnd);\r\n                tempDate = new Date(dateStartDay2.getFullYear(), dateStartDay2.getMonth());\r\n                if(tempDate>lastDay){\r\n                    loop=false;\r\n                    break;\r\n                }\r\n            }\r\n            arr.push({\"timesStart\":timesStart,\"timesEnd\":timesEnd});\r\n            index++;\r\n            if(index>10){\r\n                loop=false;\r\n                break;\r\n            }\r\n        }\r\n        // console.log(arr);\r\n        return arr;\r\n    }\r\n    function dateToolAddZero(num){\r\n        return num<10?\'0\'+num:num;\r\n    }\r\n    // weekCount(\'2008-2\');\r\n    // weekCount(\'2018-1\');\r\n    // weekCount(\'2018-4\');\r\n    // weekCount(\'2017-12\');\r\n    // weekCount(\'2018-12\');\r\n    // weekCount(\'2019-1\');\r\n    //年份展示\r\n    function yearsShow(id,time,df) {\r\n        $(id).html(\"\");\r\n        $(id).append(\"<option value=\'\'>--年--</option>\");\r\n        var date=new Date;\r\n        var year=date.getFullYear();\r\n        var month=date.getMonth()+1;\r\n        var len = 0;\r\n        if(time){\r\n            len = time;\r\n        }\r\n        for (var i=year;i>=len;i--){\r\n            $(id).append(\"<option value=\'\"+i+\"\'>\"+i+\"</option>\");\r\n        }\r\n        if(df){\r\n            $(id).val(year)\r\n        }\r\n    }\r\n    //月份展示\r\n    function monthShow(id,df) {\r\n        $(id).html(\"\");\r\n        $(id).append(\"<option value=\'\'>--月--</option>\");\r\n        var date=new Date;\r\n        var month=date.getMonth()+1;\r\n        for (var i=1;i<=12;i++){\r\n            var v = i<10?(\'0\'+i):i;\r\n            $(id).append(\"<option value=\'\"+v+\"\'>\"+i+\"</option>\");\r\n        }\r\n        if(df){\r\n            $(id).val(month<10?(\'0\'+month):month);\r\n        }\r\n    }\r\n    monthShow(\".month-crm\",true);\r\n    yearsShow(\".year-crm\",2014,true);\r\n</script>\r\n</html>
    '); +INSERT INTO `ape_document_article` VALUES (104, '

    新文章

    '); +INSERT INTO `ape_document_article` VALUES (107, '

    22222

    '); +INSERT INTO `ape_document_article` VALUES (108, '

    2131231

    '); +INSERT INTO `ape_document_article` VALUES (109, '

    222

    '); -- ---------------------------- -- Table structure for ape_document_category @@ -350,13 +563,14 @@ CREATE TABLE `ape_document_category` ( `create_time` int(10) UNSIGNED NOT NULL DEFAULT 0 COMMENT '创建时间', `update_time` int(10) UNSIGNED NOT NULL DEFAULT 0 COMMENT '更新时间', PRIMARY KEY (`id`) USING BTREE -) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '分类表' ROW_FORMAT = DYNAMIC; +) ENGINE = InnoDB AUTO_INCREMENT = 4 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '分类表' ROW_FORMAT = DYNAMIC; -- ---------------------------- -- Records of ape_document_category -- ---------------------------- -INSERT INTO `ape_document_category` VALUES (1, '关于小站', '', '', 0, 0, 99, '关于小站', '关于小站,源码云,源码云博客,关于源码云博客', '源码云博客,源码云博客网站', 1, 'list_default.html', '', 49, 0, 1642089484); -INSERT INTO `ape_document_category` VALUES (2, '编程资料', '', '', 1, 0, 0, '', '', '', 1, 'list_default.html', '', 30, 0, 0); +INSERT INTO `ape_document_category` VALUES (1, '关于小站', '', '', 0, 0, 99, '关于小站', '关于小站,源码云,源码云博客,关于源码云博客', '源码云博客,源码云博客网站', 1, 'list_default.html', '', 52, 0, 1642089484); +INSERT INTO `ape_document_category` VALUES (2, '编程资料', '', '', 0, 0, 0, '', '', '', 1, 'list_default.html', '', 55, 0, 1649562875); +INSERT INTO `ape_document_category` VALUES (3, 'php', 'php', '', 1, 2, 0, '', '', '', 1, 'list_default.html', '', 23, 0, 0); -- ---------------------------- -- Table structure for ape_document_category_content @@ -372,6 +586,7 @@ CREATE TABLE `ape_document_category_content` ( -- Records of ape_document_category_content -- ---------------------------- INSERT INTO `ape_document_category_content` VALUES (2, ''); +INSERT INTO `ape_document_category_content` VALUES (3, ''); -- ---------------------------- -- Table structure for ape_document_product @@ -569,7 +784,7 @@ CREATE TABLE `ape_tag` ( `create_time` int(11) NOT NULL DEFAULT 0, `update_time` int(11) NOT NULL DEFAULT 0, PRIMARY KEY (`id`) USING BTREE -) ENGINE = InnoDB AUTO_INCREMENT = 43 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '标签表' ROW_FORMAT = DYNAMIC; +) ENGINE = InnoDB AUTO_INCREMENT = 44 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '标签表' ROW_FORMAT = DYNAMIC; -- ---------------------------- -- Records of ape_tag @@ -577,6 +792,7 @@ CREATE TABLE `ape_tag` ( INSERT INTO `ape_tag` VALUES (40, '源码云', 1, 1, 1646022464, 1646022464); INSERT INTO `ape_tag` VALUES (41, '博客', 1, 1, 1646022464, 1646022464); INSERT INTO `ape_tag` VALUES (42, '源码云博客', 1, 1, 1646022464, 1646022464); +INSERT INTO `ape_tag` VALUES (43, '新文章', 104, 1, 1649556547, 1649556547); -- ---------------------------- -- Table structure for ape_url_log diff --git a/public/upload/image/20220410/611aab371fb34fc01b741a46ee1a360f.jpeg b/public/upload/image/20220410/611aab371fb34fc01b741a46ee1a360f.jpeg new file mode 100644 index 0000000..ee81edd Binary files /dev/null and b/public/upload/image/20220410/611aab371fb34fc01b741a46ee1a360f.jpeg differ diff --git a/public/upload/image/20220601/0ae3eaf3371fdc892dc592a94236a8ba.jpg b/public/upload/image/20220601/0ae3eaf3371fdc892dc592a94236a8ba.jpg new file mode 100644 index 0000000..073b1d1 Binary files /dev/null and b/public/upload/image/20220601/0ae3eaf3371fdc892dc592a94236a8ba.jpg differ diff --git a/public/upload/image/20220601/35bf7a1f725be872e1dbac735f86d57e.jpg b/public/upload/image/20220601/35bf7a1f725be872e1dbac735f86d57e.jpg new file mode 100644 index 0000000..533c340 Binary files /dev/null and b/public/upload/image/20220601/35bf7a1f725be872e1dbac735f86d57e.jpg differ