友儿屋 - PHP
type: channel
link: https://niuzheng.net/tag/PHP/
items: 超详细！ES 安装配置全攻略及 PHP 简单使用
items: 一步到位！Sphinx 安装配置全流程，PHP 轻松对接
items: php使用get_browser函数获取客户端浏览器信息
items: 简单用php压缩css、js输出
items: (防抖) 前后端防重复提交常用的那些方法
items: 基于php操作MongoDB的那些基本用法大全
items: php version >=8.0 传参解包
items: php实现图片叠加
items: Captcha验证码类
items: php 的 file_put_content 写入文件编码问题

超详细！ES 安装配置全攻略及 PHP 简单使用
type: item
date: 2025-02-28T15:23:00+08:00
description: 遭遇了 “黑天鹅” 事件近期真是遭遇了 “黑天鹅” 事件，公司因卷入非法问题，面临一系列棘手处理，无奈之下只得遣散全体员工，我也因此瞬间失业。原本按部就班的工作节奏戛然而止，每天醒来，看着毫无安排的一天，心里满是茫然与失落。与其在这种不确定中焦虑徘徊，倒不如主动出击，给自己找点事儿做。我打算投身到文档撰写中，既能有效填补空闲时间，让生活重回正轨，也能借此梳理过往积累的知识与经验，为未来求职筑牢根基，让这段意外失业的日子，不至于虚度 。回顾上一篇我们一同探索了 Sphinx 这个强大的全文搜索引擎，从它的功能特性到安装配置，相信大家对如何利用 Sphinx 搭建高效搜索系统有了清晰认知。不过技术的世界从不止步，在搜索领域，还有一位 “大咖”——Elasticsearch（简称 ES），它凭借分布式、高扩展、实时搜索等卓越优势，在企业级应用中大放异彩。这一篇，就让我们把目光聚焦 ES，深入剖析它的安装配置流程，探寻如何在 PHP 开发环境里，巧妙借助 ES 的力量，实现更智能、更高速的数据检索，解锁不一样的搜索体验。什么是Elasticsearch？它有什么优缺点？和 sphinx 相比，差异在哪里？Elasticsearch 是基于 Lucene 的分布式开源搜索引擎，用于全文搜索、数据分析等。优点是分布式、实时性强、功能丰富。缺点是硬件要求高、索引维护成本高。与 Sphinx 相比，ES 分布式和扩展性更好，功能更全面；Sphinx 在特定场景性能较好，配置相对简单，更适合中小规模数据。安装和配置Elasticsearch官网下载地址服务器：CentOS7,Java版本21.0.2(Elasticsearch基于Java开发)没有Java环境的自行去下载合适的版本，并把java加到环境变量中。sudo vim /etc/profile export JAVA_HOME=/www/server/java/jdk-21.0.2 export PATH=$JAVA_HOME/bin:$PATH安装# 创建存放Elasticsearch软件目录 mkdir -p /usr/local/es/ # 进入/usr/local/es/文件夹 cd /usr/local/es/ # 下载对应的glibc版本的sphinx软件包 wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-8.17.2-linux-x86_64.tar.gz # 解压 tar -zxvf elasticsearch-8.17.2-linux-x86_64.tar.gz # es 禁止以root用户运行，所以我们创建一个组和用户，用于启动es # 创建组 elasticsearch groupadd elasticsearch # 创建用户，指定用户所在的组 useradd youer -g elasticsearch # 设置用户密码 passwd youer配置# 进入/usr/local/es/elasticsearch-8.17.2/config 配置目录，修改以下配置 cd /usr/local/es/elasticsearch-8.17.2/config vim elasticsearch.yml # 找到以下配置并且修改 =============================================================================== # 集群名称，用于标识一个 Elasticsearch 集群， # 同一集群内的节点需要具有相同的集群名称才能相互通信并组成集群。 # 这里设置为 "my-es"，你可以根据实际情况修改为合适的名称。 cluster.name: my-es # 节点名称，用于在集群中唯一标识一个节点。 # 每个节点都应有一个独特的名称，这里设置为 "node-1"， # 可以根据实际需求进行调整。 node.name: node-1 # 绑定的网络地址，"0.0.0.0" 表示该节点将监听所有可用的网络接口， # 使得其他机器可以通过网络访问该 Elasticsearch 节点。 # 这在生产环境中需要谨慎配置，以确保安全性。 network.host: 0.0.0.0 # HTTP 服务端口，Elasticsearch 通过此端口提供 HTTP 接口供外部访问， # 这里设置为 9200，是 Elasticsearch 默认的 HTTP 端口， # 可根据实际情况修改，但要避免与其他服务端口冲突。 http.port: 9200 # 种子节点列表，用于在节点启动时发现集群中的其他节点。 # 这里指定了 "1…

一步到位！Sphinx 安装配置全流程，PHP 轻松对接
type: item
date: 2025-02-28T13:11:00+08:00
description: 遭遇了 “黑天鹅” 事件近期真是遭遇了 “黑天鹅” 事件，公司因卷入非法问题，面临一系列棘手处理，无奈之下只得遣散全体员工，我也因此瞬间失业。原本按部就班的工作节奏戛然而止，每天醒来，看着毫无安排的一天，心里满是茫然与失落。与其在这种不确定中焦虑徘徊，倒不如主动出击，给自己找点事儿做。我打算投身到文档撰写中，既能有效填补空闲时间，让生活重回正轨，也能借此梳理过往积累的知识与经验，为未来求职筑牢根基，让这段意外失业的日子，不至于虚度 。什么是Sphinx? 有什么优缺点呢？phinx 是开源全文搜索引擎。优点是高性能、功能丰富、可扩展性好、多语言支持、开源成本低；缺点是配置复杂、对内存要求高、实时性有限、缺乏图形化管理界面。安装和配置sphinx官网下载页面服务器：CentOS7，glibc版本2.17安装# 创建存放sphinx软件目录 mkdir -p /usr/local/sphinx/ # 进入/usr/local/sphinx/文件夹 cd /usr/local/sphinx/ # 下载对应的glibc版本的sphinx软件包 wget https://sphinxsearch.com/files/sphinx-3.7.1-da9f8a4-linux-amd64-glibc2.17.tar.gz # 解压 tar -zxvf sphinx-3.7.1-da9f8a4-linux-amd64-glibc2.17.tar.gz配置# 进入到配置目录 cd /usr/local/sphinx/sphinx-3.7.1/etc/ # 创建文件，把配置粘贴进去 vim sphinx.conf ====================================================== # 通用配置部分，定义一些全局的设置 common { # 数据目录，用于存放索引文件和其他相关数据 datadir = ./sphinxdata } # 数据源配置，这里以 MySQL 数据库为例 source names_1_source { # 数据源类型为 MySQL type = mysql # 数据库主机地址，使用 127.0.0.1 以确保端口配置生效 sql_host = 127.0.0.1 # 数据库用户名 sql_user = active # 数据库密码 sql_pass = PcjcrN53sR8bdZyx # 要连接的数据库名 sql_db = active # 数据库端口号，默认是 3306 sql_port = 3306 # SQL 查询语句，用于从数据库中获取要索引的数据 sql_query = SELECT id, surname, name, first, second, gender, type, score, details FROM names_1 # 在执行查询前设置字符集为 UTF-8，确保中文等字符能正确处理 sql_query_pre = SET NAMES utf8mb4 } # 索引配置 index names_1_index { # 索引类型为普通索引 type = plain # 关联的数据源 source = names_1_source # 要进行全文搜索的字段 field = surname, details # 定义属性，用于排序、过滤等操作 attr_uint = gender, type # 无符号整数类型的属性 attr_float = score # 浮点数类型的属性 attr_string = name, first, second # 字符串类型的属性 # 字符集表，涵盖了数字、英文字母（大小写统一）、中文、日文、韩文等字符范围 # charset_table = # 最小词长度，设置为 1 表示单字符也会被索引，适用于中文和单字母搜索 min_word_len = 1 # 词形处理方式，这里设置为不进行词形处理 morphology = none # N - gram 长度，设置为 1 表示按单字符进行 N - gram 索引，有助于中文搜索 ngram_len = 1 # 指定用于 N - gram 索引的字符范围，这里包含了中文、日文、韩文等字符 ngram_chars = U+4E00..U+9FBB, U+3400..U+4DB5, U+20000..U+2A6D6, U+FA0E, U+FA0F, U+FA11, U+FA13, U+FA14, U+FA1F, U+FA21, U+FA23, U+FA24, U+FA27, U+FA28, U+FA29, U+3105..U+312C, U+31A0..U+31B7, U+3041, U+304…

php使用get_browser函数获取客户端浏览器信息
type: item
date: 2023-09-08T12:31:00+08:00
description: 当你使用get_browser函数时出现一下错误提示Warning: get_browser(): browscap ini directive not set in ...因为get_browser的实现原理是通过查找browscap.ini配置文件中的浏览器信息，从而尝试检测用户的浏览器所具有的功能。既然依赖于browscap.ini配置文件，就需要去下载这个配置文件，因为这个浏览器版本等都是处于经常变化的状态，所以这种文件必须到browscap官网下载而且保持更新。下载browscap配置文件，版本自行根据需要下载，然后配置php.ini，重启php-fpm[browscap] browscap=/www/server/php/74/etc/lite_php_browscap.ini下载地址这是browscap.ini的一个特殊版本，仅供PHP用户使用！php_browscap.ini (23,321 KB)这是php_browscap.ini的一个更大版本，包含了所有新属性。full_php_browscap.ini (113,097 KB)这是php_browscap.ini文件的较小版本，包含主要的浏览器和搜索引擎。此文件适用于大多数网站。lite_php_browscap.ini (1,114 KB)

简单用php压缩css、js输出
type: item
date: 2023-09-08T09:33:00+08:00
description: 所谓的压缩，无非就是把换行空格等符号替换为空css<?php header('Content-type: text/css'); ob_start("compress"); function compress($buffer) { $buffer = preg_replace('!/\*[^*]*\*+([^/][^*]*\*+)*/!', '', $buffer); $buffer = str_replace(array(" ", "\r", "\n", "\t", ' ', ' ', ' '), '', $buffer); return $buffer; } //文件太多的话可以自行写一个递归 include('第一个CSS文件'); //例如当前PHP文件下的 ./test.css include('第二个CSS文件'); //复制调用更多css文件 ./test1.css ob_end_flush(); //浏览器打开，输出压缩后的内容 ?>js<?php error_reporting(E_ALL & ~E_NOTICE); if (extension_loaded('zlib')) { ob_start('ob_gzhandler'); } header("content-type:application/x-javascript; charset: UTF-8"); header("cache-control: must-revalidate"); $offset = 60 * 60 * 24; //js文件的距离现在的过期时间，这里设置为一天 $expire = "expires: " . gmdate("D, d M Y H:i:s", time() + $offset) . " GMT"; header($expire); ob_start("compress"); function compress($buffer) { $buffer = preg_replace('/\/\/.*/', '', $buffer); $buffer = str_replace(array(" ", "\r", "\n", "\t", ' ', ' ', ' '), '', $buffer); return $buffer; } include('js文件一'); //例如当前PHP文件下的main.js include('js文件二'); //复制调用更多JS文件 if (extension_loaded('zlib')) { ob_end_flush(); //输出压缩后的内容 } ?>

(防抖) 前后端防重复提交常用的那些方法
type: item
date: 2023-09-07T14:59:18+08:00
description: 防抖（Debounce）是一种防止重复提交的策略，它通过延迟一定时间来合并连续的操作，以确保只执行一次。前端 JavaScript 实现function debounce(func, delay) { let timer; return function() { clearTimeout(timer); timer = setTimeout(() => { func.apply(this, arguments); }, delay); }; } const submitForm = debounce(function() { // 在这里执行表单提交操作 }, 1000); // 延迟 1 秒执行 Submit 防抖Session Token防抖// 生成随机的 token $token = md5(uniqid()); // 存储 token 到会话 $_SESSION['submit_token'] = $token; // 在表单中嵌入 token echo ' '; // 处理表单提交时的校验 if ($_POST['submit_token'] === $_SESSION['submit_token']) { // 处理表单提交 // 清除会话中的 token unset($_SESSION['submit_token']); }Token防抖（利用随机生成的 token 来防止重复提交）$token = md5(uniqid()); echo ' '; if ($_POST['submit_token'] === $token) { // 处理表单提交 }时间戳防抖$currentTime = time(); $lastSubmitTime = $_SESSION['last_submit_time'] ?? 0; if ($currentTime - $lastSubmitTime > 5) { // 处理表单提交 $_SESSION['last_submit_time'] = $currentTime; } IP地址防抖 （利用IP地址来防止相同IP的重复提交）$userIP = $_SERVER['REMOTE_ADDR']; $lastSubmitIP = $_SESSION['last_submit_ip'] ?? ''; if ($userIP !== $lastSubmitIP) { // 处理表单提交 $_SESSION['last_submit_ip'] = $userIP; } Cookie防抖 （利用Cookie来防止在一段时间内的重复提交）if (!isset($_COOKIE['submit_cookie'])) { // 处理表单提交 setcookie('submit_cookie', 'submitted', time() + 60); // 60秒内不允许重复提交 }延时防抖（在最后一次操作后的一段时间内，只执行一次提交操作）if (!isset($_SESSION['submit_timer'])) { $_SESSION['submit_timer'] = time(); } if (time() - $_SESSION['submit_timer'] > 10) { // 处理表单提交 $_SESSION['submit_timer'] = time(); } 数据库唯一性约束（利用数据库的唯一性约束来防止重复插入数据）try { // 尝试插入数据，如果插入失败会抛出异常 // 添加数据库的唯一性索引或唯一性约束以防止重复数据 } catch (Exception $e) { // 处理插入失败的情况 } 缓存防抖（利用缓存系统来记录提交状态）$cacheKey = 'submit_status_' . $userIP; if (!cache_get($cacheKey)) { // 处理表单提交 cache_set($cacheKey, 'submitted', 60); // 60秒内不允许重复提交 }验证码防抖（要求用户输入特定的验证码来提交表单，防止恶意重复提交）if ($_POST['captcha'] === $_SESSION['captcha_code']) { // 处理表单提交 // 清除验证码，以防止多次使用同一个验证码 unset($_SESSION['captcha_code']); }

基于php操作MongoDB的那些基本用法大全
type: item
date: 2022-11-14T09:57:00+08:00
description: 什么是MongoDBMongoDB 是一个介于关系数据库和非关系数据库之间的产品，是非关系数据库当中功能最丰富，最像关系数据库的。他支持的数据结构非常松散，是类似json的bson格式，因此可以存储比较复杂的数据类型。Mongo最大的特点是他支持的查询语言非常强大，其语法有点类似于面向对象的查询语言，几乎可以实现类似关系数据库单表查询的绝大部分功能，而且还支持对数据建立索引。特点高性能、易部署、易使用，存储数据非常方便。面向集合存储，易存储对象类型的数据。模式自由。支持动态查询。支持完全索引，包含内部对象。支持查询。支持复制和故障恢复。使用高效的二进制数据存储，包括大型对象（如视频等）。自动处理碎片，以支持云计算层次的扩展性。支持RUBY，PYTHON，JAVA，C ，PHP，C#等多种语言。文件存储格式为BSON（一种JSON的扩展）。使用原理- 所谓“面向集合”（Collection-Oriented），意思是数据被分组存储在数据集中，被称为一个集合（Collection)。每个集合在数据库中都有一个唯一的标识名，并且可以包含无限数目的文档。 - 集合的概念类似关系型数据库（RDBMS）里的表（table），不同的是它不需要定义任何模式（schema)。Nytro MegaRAID技术中的闪存高速缓存算法，能够快速识别数据库内大数据集中的热数据，提供一致的性能改进。 - 模式自由（schema-free)，意味着对于存储在mongodb数据库中的文件，我们不需要知道它的任何结构定义。如果需要的话，你完全可以把不同结构的文件存储在同一个数据库里。 - 存储在集合中的文档，被存储为键-值对的形式。键用于唯一标识一个文档，为字符串类型，而值则可以是各种复杂的文件类型。我们称这种存储形式为BSON（Binary Serialized Document Format）。 适用场景- MongoDB 的主要目标是在键/值存储方式（提供了高性能和高度伸缩性）和传统的RDBMS 系统（具有丰富的功能）之间架起一座桥梁，它集两者的优势于一身。根据官方网站的描述，Mongo 适用于以下场景。 - 网站数据：Mongo 非常适合实时的插入，更新与查询，并具备网站实时数据存储所需的复制及高度伸缩性。 - 缓存：由于性能很高，Mongo 也适合作为信息基础设施的缓存层。在系统重启之后，由Mongo 搭建的持久化缓存层可以避免下层的数据源过载。 - 大尺寸、低价值的数据：使用传统的关系型数据库存储一些数据时可能会比较昂贵，在此之前，很多时候程序员往往会选择传统的文件进行存储。 - 高伸缩性的场景：Mongo 非常适合由数十或数百台服务器组成的数据库，Mongo 的路线图中已经包含对MapReduce 引擎的内置支持。 - 用于对象及JSON 数据的存储：Mongo 的BSON 数据格式非常适合文档化格式的存储及查询。 不适场景- 高度事务性的系统：例如，银行或会计系统。传统的关系型数据库目前还是更适用于需要大量原子性复杂事务的应用程序。 - 传统的商业智能应用：针对特定问题的BI 数据库会产生高度优化的查询方式。对于此类应用，数据仓库可能是更合适的选择。 - 需要SQL 的问题。 Mognodb数据库连接<?php // 默认格式 (这里采用默认连接本机的27017端口，当然也可以连接远程主机。如 192.168.0.4:27017,如果端口是27017，端口可以省略。) $m = new Mongo(); //实例 (数据库的用户名和密码都是admin) $m = new Mongo("mongodb://127.0.0.1:27017/admin:admin");插入数据<?php //这里采用默认连接本机的27017端口，当然你也可以连接远程主机如192.168.0.4:27017 //如果端口是27017，端口可以省略 $m = new Mongo("mongodb://127.0.0.1:27017/admin:admin"); //选择comedy数据库，如果以前没该数据库会自动创建，也可以用$m->selectDB("comedy"); $db = $m->comedy; //选择comedy里面的collection集合，相当于RDBMS里面的表，也可以使用 $collection = $db->collection; $db->selectCollection("collection"); /*********添加一个元素**************/ $obj = array("title" => "php1", "author" => "Bill Watterson"); //将$obj 添加到$collection 集合中 $…

php version >=8.0 传参解包
type: item
date: 2022-09-09T17:02:00+08:00
description: 其他语言大多都有函数传参解包的功能,php8也加入了这个功能。php version < 8<?php function test(...$arg) { var_dump($arg); } test(); //array(0) { } test(NULL); //array(1) { [0]=> NULL } test("foo", "bar"); //array(2) { [0]=> string(3) "foo" [1]=> string(3) "bar" } test(NULL, array(), "dummy"); //array(3) { [0]=> NULL [1]=>[] [2]=> string(5) "dummy" } function test1($a, $b = NULL, $c = NULL, $d = NULL, $e = NULL) { var_dump($a, $b, $c, $d, $e); } $arg = array( "First arg", NULL, NULL, NULL, "Fifth arg", ); test1(...$arguments); // string(14) "First arg" // NULL // NULL // NULL // string(14) "Fifth arg"php version >=8<?php function dummy($a, $b = NULL, $c = NULL, $d = NULL, $e = NULL) { var_dump($a, $b, $c, $d, $e); } dummy(a:"dummy", e:"foo"); // string(5) "dummy" // NULL // NULL // NULL // string(3) "foo"

php实现图片叠加
type: item
date: 2022-08-19T13:29:43+08:00
description: php实现图片合并<?php //$qrc 原图 //$bg 背景图 //$new 新图 //$text 文字 //$font 字体 function mergeImages($qrc, $bg, $new, $text, $font) { //创建图片的实例 $dst = imagecreatefromstring(file_get_contents($bg)); $src = imagecreatefromstring(file_get_contents($qrc)); //获取覆盖图图片的宽高 list($src_w, $src_h) = getimagesize($qrc); //将覆盖图复制到目标图片上，最后个参数100是设置透明度（100是不透明），这里实现不透明效果 imagecopymerge($dst, $src, 1200, 210, 0, 0, $src_w, $src_h, 100); //位置可以自己调试 imagepng($dst, $new);//根据需要生成相应的图片 imagedestroy($dst); imagedestroy($src); $image = imagecreatefrompng($new); if ($text && $font) { $color = imagecolorallocate($image, 0, 0, 0); // 文字颜色 imagettftext($image, 40, 0, 250, 600, $color, $font, $text);// 创建文字 } imagepng($image, $new); return $new; }

Captcha验证码类
type: item
date: 2022-07-19T17:14:00+08:00
description: 验证码文字扭曲、旋转，使用不同字体，添加干扰码等<?php /** * 安全验证码 * 安全的验证码要：验证码文字扭曲、旋转，使用不同字体，添加干扰码 */ class Captcha { /** * 验证码的session的下标 * * @var string */ public static $seKey = 'h5.07073.com'; public static $expire = 300; // 验证码过期时间（s） /** * 验证码中使用的字符，01IO容易混淆，建议不用 * * @var string */ public static $codeSet = '2345679ACDEFGHJKLMNPQRTUVWXY'; public static $fontSize = 20; // 验证码字体大小(px) public static $useCurve = true; // 是否画混淆曲线 public static $useNoise = false; // 是否添加杂点 public static $imageH = 0; // 验证码图片宽 public static $imageL = 0; // 验证码图片长 public static $length = 4; // 验证码位数 public static $bg = array(243, 251, 254); // 背景 protected static $_image = null; // 验证码图片实例 protected static $_color = null; // 验证码字体颜色 /** * 输出验证码并把验证码的值保存的session中 * 验证码保存到session的格式为： $_SESSION[self::$seKey] = array('code' => '验证码值', 'time' => '验证码创建时间'); */ public static function entry() { // 图片宽(px) self::$imageL || self::$imageL = self::$length * self::$fontSize * 1.5 + self::$fontSize*1.5; // 图片高(px) self::$imageH || self::$imageH = self::$fontSize * 2; // 建立一幅 self::$imageL x self::$imageH 的图像 self::$_image = imagecreate(self::$imageL, self::$imageH); // 设置背景 imagecolorallocate(self::$_image, self::$bg[0], self::$bg[1], self::$bg[2]); // 验证码字体随机颜色 self::$_color = imagecolorallocate(self::$_image, mt_rand(1,120), mt_rand(1,120), mt_rand(1,120)); // 验证码使用随机字体 $ttf = dirname(__FILE__) . '/ttfs/' . 4 . '.ttf'; //$ttf = dirname(__FILE__) . '/ttfs/' . mt_rand(1, 20) . '.ttf'; if (self::$useNoise) { // 绘杂点 self::_writeNoise(); } if (self::$useCurve) { // 绘干扰线 self::_writeCurve(); } // 绘验证码 $code = array(); // 验证码 $codeNX = 0; // 验证码第N个字符的左边距 for ($i = 0; $i<self::$length; $i++) { $code[$i] = self::$codeSet[mt_rand(0, 27)]; $codeNX += mt_rand(self::$fontSize*1.2, self::$fontSize*1.5); // 写一个验证码字符 imagettftext(self::$_image, self::$fontSize, mt_rand(-10, 70), $codeNX, self::$fontSize*1.5, self::$_color, $ttf, $code[$i]); } // 保存验证码 isset($_SESSION) || session_start(); $_SESSION[self::$seKey]['code'] = join('', $co…

php 的 file_put_content 写入文件编码问题
type: item
date: 2022-06-16T10:53:00+08:00
description: <?php $str = "中文"; $filename = '1.txt'; file_put_contents($filename,$str); echo '测试1-检测本地文件编码：' . detect_encoding($filename) . ' '; $filename = '2.txt'; file_put_contents($filename,mb_convert_encoding($str,'UTF-8',mb_detect_encoding($str))); echo '测试2-检测本地文件编码：' . detect_encoding($filename) . ' '; $fp =fopen($filename,"w+"); $header ="\xef\xbb\xbf"; fwrite($fp,$header); fwrite($fp,$str); fclose($fp); echo '测试3-检测本地文件编码：' . detect_encoding($filename) . ' '; function detect_encoding($file) { $list = ['GBK', 'UTF-8', 'UTF-16LE', 'UTF-16BE', 'ISO-8859-1']; $str = file_get_contents($file); foreach ($list as $item) { $tmp = mb_convert_encoding($str, $item, $item); if (md5($tmp) == md5($str)) { return $item; } } return null; }UTF-8编码的TXT文件必须以0xef , 0xbb , 0xbf三个字符开头！