首页
关于
Search
1
给你10个市场数据调研报告的免费下载网站!以后竞品数据就从这里找!
183 阅读
2
php接口优化 使用curl_multi_init批量请求
144 阅读
3
《从菜鸟到大师之路 ElasticSearch 篇》
107 阅读
4
2024年备考系统架构设计师
104 阅读
5
PHP 文件I/O
92 阅读
php
thinkphp
laravel
工具
开源
mysql
数据结构
总结
思维逻辑
令人感动的创富故事
读书笔记
前端
vue
js
css
书籍
开源之旅
架构
消息队列
docker
教程
代码片段
redis
服务器
nginx
linux
科普
java
c
ElasticSearch
测试
php进阶
php基础
登录
Search
标签搜索
php函数
php语法
性能优化
安全
错误和异常处理
问题
vue
Composer
Session
缓存
框架
Swoole
api
并发
异步
正则表达式
php-fpm
mysql 索引
开发规范
协程
dafenqi
累计撰写
786
篇文章
累计收到
31
条评论
首页
栏目
php
thinkphp
laravel
工具
开源
mysql
数据结构
总结
思维逻辑
令人感动的创富故事
读书笔记
前端
vue
js
css
书籍
开源之旅
架构
消息队列
docker
教程
代码片段
副业
redis
服务器
nginx
linux
科普
java
c
ElasticSearch
测试
php进阶
php基础
页面
关于
搜索到
560
篇与
的结果
2023-12-28
PHP Base64 、Blob、File间的相互转换
PHP Base64 、Blob、File间的相互转换前言在获取时,遇到需要转换格式的情况,所以记录下来分享。正文一、格式的基本介绍Base64Base64是网络上最常见的用于传输8Bit字节码的编码方式之一,Base64就是一种基于64个可打印字符来表示二进制数据的方法举个例子BlobBlob 对象表示一个不可变、原始数据的类文件对象。它的数据可以按文本或二进制的格式进行读取,也可以转换成 ReadableStream来用于数据操作。举个例子File文件(File)接口提供有关文件的信息,并允许网页中的 JavaScript 访问其内容。 举个例子就不过多介绍了,主要来讲如果转换。二、如何判断这三种格式1.判断是否为Base64字符串// 判断是否为base64格式字符串 function isBase64(str) { //正则表达式判断 var reg = /^\s*data:([a-z]+\/[a-z0-9-+.]+(;[a-z-]+=[a-z0-9-]+)?)?(;base64)?,([a-z0-9!$&',()*+;=\-._~:@\/?%\s]*?)\s*$/i; return reg.test(str) //返回 true or false }2.判断是否为Blob对象console.log(data instanceof Blob) //ture or false3.判断是否为File对象console.log(data instanceof File && !data instanceof Blob) //ture or falsePS:Blob和File都用instanceof来判断是否为对应类型数据有一点需要注意,File对象也是Blob对象 ,因为File继承于Blob,所以其中的判断逻辑可以自己定义。三、格式之间的转换1.Base64转换为Filefunction dataURLtoFile(dataurl, filename) { var arr = dataurl.split(','), mime = arr[0].match(/:(.*?);/)[1], bstr = atob(arr[1]), n = bstr.length, u8arr = new Uint8Array(n); while (n--) { u8arr[n] = bstr.charCodeAt(n); } return new File([u8arr], filename, { type: mime }); }需要传两个参数,第一个是数据,第二个是自定义文件名字符串2.Base64转换为Blobfunction dataURLtoBlob(dataurl, filename) { var arr = dataurl.split(','), mime = arr[0].match(/:(.*?);/)[1], bstr = atob(arr[1]), n = bstr.length, u8arr = new Uint8Array(n); while (n--) { u8arr[n] = bstr.charCodeAt(n); } return new Blob([u8arr], { type: mime }); }和转File基本一样,就最后一句return不一样3.Blob转Filefunction blobToFile(blob) { return new File([blob], 'screenshot.png', { type: 'image/jpeg' }) }这里和Base64转File其实用的都是new File()这个方法,上面的第二个参数是传进来的,这里是定死的,这个参数不是很重要,可以自行修改函数,方法都已经提供了,直接使用就可以。
2023年12月28日
8 阅读
0 评论
0 点赞
2023-12-28
“重构” PHP 代码!
“重构” PHP 代码!重构指的是在不改变原有功能的情况下,修改或者重新编写代码。下面的例子中,我将向你展示如何更好地编写代码。1 - 表现力这可能只是一个简单的技巧,但编写富有表现力的代码可以大大改进我们的代码。总是让代码自我解释,这样未来的你或其他开发人员都能知道代码中发生了什么。不过也有开发人员表示,命名是编程中最困难的事情之一。这就是为什么这不像听起来那么容易的原因之一。示例 #1 - 命名之前// ❌ 这个方法是用来做什么的,方法名表达并不清晰 // ❌ 是设置状态还是检查状态呢? $status = $user->status('pending');之后// ✅ 通过添加 is,使方法名表达的意图更清晰 // ✅ 检测用户状态是否与给定状态相等 // ✅ 同时新变量名让我们可以推断它是布尔值 $isUserPending = $user->isStatus('pending');示例 #2 - 命名之前// ❌ 这个类返回的是什么?类名?类全名?还是类路径? return $factory->getTargetClass();之后// ✅ 我们获取的是类路径 // ✅ 如果用户想要类名?则找错了方法 return $factory->getTargetClassPath();示例 #3 - 提取之前// ❌ 重复的代码 ( "file_get_contents", "base_path" 方法以及文件扩展) // ❌ 此刻,我们不去关心如何获得code examples public function setCodeExamples(string $exampleBefore, string $exampleAfter) { $this->exampleBefore = file_get_contents(base_path("$exampleBefore.md")); $this->exampleAfter = file_get_contents(base_path("$exampleAfter.md")); }之后public function setCodeExamples(string $exampleBefore, string $exampleAfter) { // ✅ 代码直接说明了我们的意图:获取code example(不关注如何获取) $this->exampleBefore = $this->getCodeExample($exampleBefore); $this->exampleAfter = $this->getCodeExample($exampleAfter); } // ✅ 这个新方法可多次调用 private function getCodeExample(string $exampleName): string { return file_get_contents(base_path("$exampleName.md")); }示例 #4 - 提取之前// ❌ 多重 where 语句,使阅读变得困难 // ❌ 意图究竟是什么呢? User::whereNotNull('subscribed')->where('status', 'active');之后// ✅ 这个新的scope方法说明了发生了什么事 // ✅ 如果我们需要了解更多细节,可以进入这个scope方法内部去了解 // ✅ "subscribed" scope 方法可在其他地方使用 User::subscribed();示例 #5 - 提取这是我之前项目的一个例子。我们用命令行导入用户。ImportUsersCommand 类中含有一个 handle 方法,用来处理任务。之前protected function handle() { // ❌ 这个方法包含太多代码 $url = $this->option('url') ?: $this->ask('Please provide the URL for the import:'); $importResponse = $this->http->get($url); // ❌ 进度条对用户很有用,不过却让代码显得杂乱 $bar = $this->output->createProgressBar($importResponse->count()); $bar->start(); $this->userRepository->truncate(); collect($importResponse->results)->each(function (array $attributes) use ($bar) { $this->userRepository->create($attributes); $bar->advance(); }); // ❌ 很难说清此处发生了哪些行为 $bar->finish(); $this->output->newLine(); $this->info('Thanks. Users have been imported.'); if($this->option('with-backup')) { $this->storage ->disk('backups') ->put(date('Y-m-d').'-import.json', $response->body()); $this->info('Backup was stored successfully.'); } }之后protected function handle(): void { // ✅ handle方法是你访问该类首先会查看的方法 // ✅ 现在可以很容易就对这个方法做了些什么有个粗略的了解 $url = $this->option('url') ?: $this->ask('Please provide the URL for the import:'); $importResponse = $this->http->get($url); $this->importUsers($importResponse->results); $this->saveBackupIfAsked($importResponse); } // ✅ 如果需要了解更多细节,可以查看这些专用的方法 protected function importUsers($userData): void { $bar = $this->output->createProgressBar(count($userData)); $bar->start(); $this->userRepository->truncate(); collect($userData)->each(function (array $attributes) use ($bar) { $this->userRepository->create($attributes); $bar->advance(); }); $bar->finish(); $this->output->newLine(); $this->info('Thanks. Users have been imported.'); } // ✅ 不要害怕使用多行代码 // ✅ 这个例子中它让我们核心的 handle 方法更为简洁 protected function saveBackupIfAsked(Response $response): void { if($this->option('with-backup')) { $this->storage ->disk('backups') ->put(date('Y-m-d').'-import.json', $response->body()); $this->info('Backup was stored successfully.'); } }2 - 提前返回提前返回指的是,我们尝试通过将结构分解为特定 case 来避免嵌套的做法。这样,我们得到了更线性的代码,更易于阅读和了解。不要害怕使用多个 return 语句。示例 #1之前public function calculateScore(User $user): int { if ($user->inactive) { $score = 0; } else { // ❌ 怎么又有一个 "if"? if ($user->hasBonus) { $score = $user->score + $this->bonus; } else { // ❌ 由于存在多个层级,大费眼神 ? $score = $user->score; } } return $score; }之后public function calculateScore(User $user): int { // ✅ 边缘用例提前检测 if ($user->inactive) { return 0; } // ✅ 每个用例都有自己的代码块,使得更容易跟进 if ($user->hasBonus) { return $user->score + $this->bonus; } return $user->score; }示例 #2之前public function sendInvoice(Invoice $invoice): void { if($user->notificationChannel === 'Slack') { $this->notifier->slack($invoice); } else { // ❌ 即使是简单的ELSE都影响代码的可读性 $this->notifier->email($invoice); } }之后public function sendInvoice(Invoice $invoice): bool { // ✅ 每个条件都易读 if($user->notificationChannel === 'Slack') { return $this->notifier->slack($invoice); } // ✅ 不用再考虑ELSE 指向哪里 return $this->notifier->email($invoice); }Note: 有时你会听到 “防卫语句” 这样的术语,它是通过提前返回实现。3 - 重构成集合 Collection在 PHP 中,我们在很多不同数据中都用到了数组。处理及转换这些数组可用功能非常有限,并且没有提供良好的体验。(array_walk, usort, etc)要处理这个问题,有一个 Collection 类的概念,可用于帮你处理数组。最为人所知的是 Laravel 中的实现,其中的 collection 类提供了许多有用的特性,用来处理数组。注意: 以下例子, 我将使用 Laravel 的 collect () 辅助函数,不过在其他框架或库中的使用方式也很相似。示例 #1之前// ❌ 这里我们有一个临时变量 $score = 0; // ❌ 用循环没有问题,不过可读性还是有改善空间 foreach($this->playedGames as $game) { $score += $game->score; } return $score;之后// ✅ 集合是带有方法的对象 // ✅ sum 方法使之更具表现力 return collect($this->playedGames) ->sum('score');示例 #2之前$users = [ [ 'id' => 801, 'name' => 'Peter', 'score' => 505, 'active' => true], [ 'id' => 844, 'name' => 'Mary', 'score' => 704, 'active' => true], [ 'id' => 542, 'name' => 'Norman', 'score' => 104, 'active' => false], ]; // 请求结果: 只显示活跃用户,以 score 排序 ["Mary(704)","Peter(505)"] $users = array_filter($users, fn ($user) => $user['active']); // ❌ usort 进行排序处理的又是哪一个对象呢?它是如何实现? usort($users, fn($a, $b) => $a['score'] < $b['score']); // ❌ 所有的转换都是分离的,不过都是users相关的 $userHighScoreTitles = array_map(fn($user) => $user['name'] . '(' . $user['score'] . ')', $users); return $userHighScoreTitles;之后$users = [ [ 'id' => 801, 'name' => 'Peter', 'score' => 505, 'active' => true], [ 'id' => 844, 'name' => 'Mary', 'score' => 704, 'active' => true], [ 'id' => 542, 'name' => 'Norman', 'score' => 104, 'active' => false], ]; // 请求结果: 只显示活跃用户,以 score 排序 ["Mary(704)","Peter(505)"] // ✅ 只传入一次users return collect($users) // ✅ 我们通过管道将其传入所有方法 ->filter(fn($user) => $user['active']) ->sortBy('score') ->map(fn($user) => "{$user['name']} ({$user['score']})" ->values() // ✅ 最后返回数组 ->toArray();4 - 一致性每一行代码都会增加少量的视觉噪音。代码越多,阅读起来就越困难。这就是为什么制定规则很重要。保持类似的东西一致将帮助您识别代码和模式。这将导致更少的噪声和更可读的代码。示例 #1之前class UserController { // ❌ 确定如何命名变量(驼峰或是蛇形等),不要混用! public function find($userId) { } } // ❌ 选择使用单数或者复数形式命名控制器,并保持一致 class InvoicesController { // ❌ 修改了样式,如花扣号的位置,影响可读性 public function find($user_id) { } }之后class UserController { // ✅ 所有变量驼峰式命名 public function find($userId) { } } // ✅ 控制器命名规则一致(此处都使用单数) class InvoiceController { // ✅ 花括号的位置(格式)一致,使代码更为可读 public function find($userId) { } }示例 #2之前class PdfExporter { // ❌ "handle" 和 "export" 是类似方法的不同名称 public function handle(Collection $items): void { // export items... } } class CsvExporter { public function export(Collection $items): void { // export items... } } // ❌ 使用时你会疑惑它们是否处理相似的任务 // ❌ 你可能需要再去查看类源码进行确定 $pdfExport->handle(); $csvExporter->export();之后// ✅ 可通过接口提供通用规则保持一致性 interface Exporter { public function export(Collection $items): void; } class PdfExporter implements Exporter { public function export(Collection $items): void { // export items... } } class CsvExporter implements Exporter { public function export(Collection $items): void { // export items... } } // ✅ 对类似的任务使用相同的方法名,更具可读性 // ✅ 不用再去查看类源码,变可知它们都用在导出数据 $pdfExport->export(); $csvExporter->export();重构 ❤️ 测试我已经提到过重构不会改变代码的功能。这在运行测试时很方便,因为它们也应该在重构之后工作。这就是为什么我只有在有测试的时候才开始重构代码。他们将确保我不会无意中更改代码的行为。所以别忘了写测试,甚至去 TDD。
2023年12月28日
15 阅读
0 评论
0 点赞
2023-12-28
PHP预处理查询如何防止SQL注入?
PHP预处理查询如何防止SQL注入?目前最有效的防止 sql 注入的方式使用预处理语句和参数化查询。以最常用的 PHP PDO 扩展为例。官方文档中对预处理语句的介绍什么是预处理语句?可以把它看作是想要运行的 SQL 的一种编译过的模板,它可以使用变量参数进行定制。预处理语句的两大好处:1.查询仅需解析(或预处理)一次,但可以用相同或不同的参数执行多次。当查询准备好后,数据库将分析、编译和优化执行该查询的计划。对于复杂的查询,此过程要花费较长的时间,如果需要以不同参数多次重复相同的查询,那么该过程将大大降低应用程序的速度。通过使用预处理语句,可以避免重复分析 / 编译 / 优化周期。简言之,预处理语句占用更少的资源,因而运行得更快。2.提供给预处理语句的参数不需要用引号括起来,驱动程序会自动处理。如果应用程序只使用预处理语句,可以确保不会发生 SQL 注入。(然而,如果查询的其他部分是由未转义的输入来构建的,则仍存在 SQL 注入的风险)。PDO 的特性在于驱动程序不支持预处理的时候,PDO 将模拟处理,此时的预处理-参数化查询过程在 PDO 的模拟器中完成。PDO 模拟器根据 DSN 中指定的字符集对输入参数进行本地转义,然后拼接成完整的 SQL 语句,发送给 MySQL 服务端。所以,PDO 模拟器能否正确的转义输入参数,是拦截 SQL 注入的关键。小于 5.3.6 的 PHP 版本,DSN (Data Source Name) 是默认忽略 charset 参数的。这时如果使用 PDO 的本地转义,仍然可能导致 SQL 注入。因此,像 Laravel 框架底层会直接设置 PDO::ATTR_EMULATE_PREPARES=false,来确保 SQL 语句和参数值在被发送到 MySQL 服务器之前不会被 PHP 解析。PHP 的实现// 查询 $calories = 150; $colour = 'red'; $sth = $dbh->prepare('SELECT name, colour, calories FROM fruit WHERE calories < :calories AND colour = :colour'); $sth->bindValue(':calories', $calories, PDO::PARAM_INT); $sth->bindValue(':colour', $colour, PDO::PARAM_STR); $sth->execute(); // 插入,修改,删除 $preparedStmt = $db->prepare('INSERT INTO table (column) VALUES (:column)'); $preparedStmt->execute(array(':column' => $unsafeValue));Laravel 的底层实现// 查询的实现 public function select($query, $bindings = [], $useReadPdo = true) { return $this->run($query, $bindings, function ($query, $bindings) use ($useReadPdo) { if ($this->pretending()) { return []; } $statement = $this->prepared( $this->getPdoForSelect($useReadPdo)->prepare($query) ); $this->bindValues($statement, $this->prepareBindings($bindings)); $statement->execute(); return $statement->fetchAll(); }); } // 修改删除的实现 public function affectingStatement($query, $bindings = []) { return $this->run($query, $bindings, function ($query, $bindings) { if ($this->pretending()) { return 0; } $statement = $this->getPdo()->prepare($query); $this->bindValues($statement, $this->prepareBindings($bindings)); $statement->execute(); $this->recordsHaveBeenModified( ($count = $statement->rowCount()) > 0 ); return $count; }); }
2023年12月28日
10 阅读
0 评论
0 点赞
2023-12-28
PHP是做什么的之应用场景非比寻常
PHP具体可以做什么?Web开发是PHP语言最擅长的!PHP可以开发像淘宝、京东等商城系统。目前国内80%以上的动态网站都在使用PHP开发,没有任何语言可以与其抗衡!全球前100万的网站中,有77%以上的网站都是通过PHP来开发的(权威网站w3techs.com 2023年2月统计)PHP具体可以做:商城开发视频/直播系统开发广告系统开发API接口开发移动端APP开发微信开发小程序开发游戏后台开发物联网开发行业站/公司官网客户CRM管理系统财务系统开发办公自动化OA系统开发等等。
2023年12月28日
11 阅读
0 评论
0 点赞
2023-12-28
PHP用流方式下载文件的优势浅析
PHP用流方式下载文件的优势浅析在PHP中,可以使用fopen()函数打开一个远程文件,并使用流来下载文件内容到本地文件。这样优点是不用将文件全部一次性放入内存中,可以避免内存溢出的问题。下面是一个示例代码:$url = 'http://example.com/file.zip'; $local_file = '/path/to/local/file.zip'; // 打开远程文件 $remote_file = fopen($url, 'r'); // 打开本地文件 $fp = fopen($local_file, 'w'); // 使用流下载文件内容 while (!feof($remote_file)) { fwrite($fp, fread($remote_file, 1024)); } // 关闭文件 fclose($remote_file); fclose($fp);在上面的代码中,使用fopen()函数打开远程文件和本地文件,然后使用fread()函数从远程文件读取内容,并使用fwrite()函数将内容写入本地文件。注意,在使用流下载文件时,需要确保服务器允许远程访问,否则可能会出现错误。使用流下载文件时,需要注意以下事项:需要确保服务器允许远程访问,否则可能会出现错误。如果本地文件已存在,会被覆盖。如果不希望覆盖,可以在打开本地文件时指定 a 模式,表示追加到文件末尾。在下载大文件时,可能会用时较长,可以使用进度条显示下载进度。如果远程文件不存在或访问出错,可能会导致下载失败。在下载文件时,可以使用 HTTP 头信息来控制文件缓存、文件类型和文件下载方式等。在下载过程中,需要确保远程文件和本地文件都已正常打开,否则可能会出现错误。在读取远程文件时,需要使用 feof () 函数检查文件是否已读完,否则可能会出现死循环。在下载过程中,需要注意带宽限制和网络状况,否则可能会导致下载速度过慢。在 PHP 中,使用 fopen () 函数打开远程文件需要在 php.ini 中启用 allow_url_fopen 选项,在 PHP 中,allow_url_fopen 选项默认是开启的。
2023年12月28日
9 阅读
0 评论
0 点赞
1
...
30
31
32
...
112