php阅读器使用教程:新手完成第一张作品的方法

运营资讯12小时前发布 jdkjadmin
0 00
php阅读器使用教程:新手完成第一张作品的方法

php阅读器使用教程:新手完成第一张作品的方法

“PHP 阅读器”不是 PHP 官方提供的一款固定软件,也没有统一的作品格式或操作界面。它通常指用 PHP 编写的网页阅读器,或者用 PHP 阅读、展示文本内容的程序。本文按后者来讲:从零搭建一个简单的网页阅读器,把一部作品及其章节显示在浏览器里。

这里说的“第一张作品”,按常见的内容管理习惯理解为“第一部作品”。完成后,你会得到一个可以本地运行的 PHP 页面:页面显示作品名、章节目录和正文,并能通过链接切换章节。示例不依赖框架、数据库或第三方扩展,适合先理解基本流程,再按实际需求扩展。

一、适用场景与功能边界

这个小程序适合用来学习 PHP、展示少量公开文本、制作个人作品样例,或验证“作品—章节—正文”的数据结构。它把数据写在 PHP 数组里,适合演示和小规模试用。

它不是完整的电子书管理系统,也不是 PDF、EPUB 阅读器。示例不包含用户注册、后台编辑、文件上传、搜索、分页、版权管理或数据持久化。作品内容要直接写入代码;修改内容后,通常需要编辑文件并重新部署。若需要管理大量作品,建议使用数据库和后台管理功能;若要阅读 PDF 或 EPUB,则需要相应格式的解析或阅读组件,不能把下面的纯文本方案当作格式转换器。

本文中的“阅读器”是由 PHP 在服务器端生成 HTML 页面,再交给浏览器显示。PHP 不会自动把一段文字变成可翻页的电子书,也不会自动保存作品。把这几个边界弄清楚,后续选择方案会容易得多。

二、准备 PHP 运行环境

需要一台已安装 PHP 的电脑或服务器。示例使用 PHP 8.0 及以上版本,采用的语法在常见 PHP 8.x 环境中可运行。它没有用到数据库、Composer 或额外扩展。可在终端检查版本:

php -v

如果系统提示找不到 php 命令,说明 PHP 尚未安装,或 PHP 可执行文件没有加入系统的 PATH。请按所用操作系统安装 PHP CLI;使用集成开发环境时,也要确认其 PHP 版本与终端使用的版本一致。

新建一个目录,例如 php-reader,在里面创建 index.php。用终端进入该目录后,执行 PHP 自带的开发服务器:

php -S 127.0.0.1:8000

浏览器访问 http://127.0.0.1:8000。这个内置服务器适合本机开发和测试,不应直接当作面向公众的生产服务器使用。上线时应根据部署环境配置正式 Web 服务器、PHP 运行方式、HTTPS 和访问控制。

三、创建第一部作品

下面先用 PHP 数组表示作品数据。每部作品有标题、作者和章节列表;每个章节有标题和正文。为便于入门,示例只放一部作品和两章内容。新手可以先原样复制,确认页面运行后再改成自己的文字。

<?php
declare(strict_types=1);

$work = [
    'title' => '雨后的车站',
    'author' => '林间',
    'chapters' => [
        [
            'title' => '第一章:晚点的列车',
            'content' => <<<'TEXT'
傍晚下起了雨。林舟走进车站时,广播刚好响起,提醒旅客列车晚点。
他把湿透的伞靠在墙边,抬头看向站台上方的时钟。
TEXT
        ],
        [
            'title' => '第二章:站台尽头',
            'content' => <<<'TEXT'
雨声渐渐小了。站台尽头亮起一盏灯,林舟在那里看见一张熟悉的车票。
他想起很多年前,也曾有人在这里等他。
TEXT
        ],
    ],
];

function escapeHtml(string $value): string
{
    return htmlspecialchars(
        $value,
        ENT_QUOTES | ENT_SUBSTITUTE,
        'UTF-8'
    );
}

$chapters = $work['chapters'];
$chapterCount = count($chapters);

if ($chapterCount === 0) {
    http_response_code(500);
    exit('作品还没有章节。');
}

$requestedChapter = filter_input(
    INPUT_GET,
    'chapter',
    FILTER_VALIDATE_INT
);

$chapterIndex = ($requestedChapter === false || $requestedChapter === null)
    ? 0
    : $requestedChapter;

if ($chapterIndex < 0 || $chapterIndex >= $chapterCount) {
    http_response_code(404);
    exit('章节不存在。');
}

$currentChapter = $chapters[$chapterIndex];

$previousIndex = $chapterIndex - 1;
$nextIndex = $chapterIndex + 1;
?>
<!doctype html>
<html lang="zh-CN">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title><?= escapeHtml($work['title']) ?></title>
    <style>
        body {
            max-width: 760px;
            margin: 2rem auto;
            padding: 0 1rem;
            color: #222;
            font: 18px/1.9 sans-serif;
        }
        nav a { margin-right: 1rem; }
        .chapter-list { padding-left: 1.5rem; }
        .content { white-space: pre-wrap; }
        .muted { color: #666; font-size: 0.9em; }
    </style>
</head>
<body>
    <header>
        <h1><?= escapeHtml($work['title']) ?></h1>
        <p class="muted">作者:<?= escapeHtml($work['author']) ?></p>
    </header>

    <nav aria-label="章节目录">
        <h2>章节目录</h2>
        <ol class="chapter-list">
            <?php foreach ($chapters as $index => $chapter): ?>
                <li>
                    <a href="?chapter=<?= $index ?>">
                        <?= escapeHtml($chapter['title']) ?>
                    </a>
                </li>
            <?php endforeach; ?>
        </ol>
    </nav>

    <main>
        <h2><?= escapeHtml($currentChapter['title']) ?></h2>
        <div class="content"><?= escapeHtml($currentChapter['content']) ?></div>
    </main>

    <nav aria-label="章节翻页">
        <?php if ($previousIndex >= 0): ?>
            <a href="?chapter=<?= $previousIndex ?>">上一章</a>
        <?php endif; ?>

        <?php if ($nextIndex < $chapterCount): ?>
            <a href="?chapter=<?= $nextIndex ?>">下一章</a>
        <?php endif; ?>
    </nav>
</body>
</html>

这里使用 PHP 的 nowdoc 写正文。nowdoc 以 <<<'TEXT' 开始,直到单独一行的 TEXT 结束,正文里的引号不会被当作 PHP 字符串语法处理。结束标记应单独占一行,且不要在标记后再写其他字符;若 PHP 报语法错误,先检查这一点,以及复制代码时有没有漏掉分号、括号或引号。

四、运行后页面做了什么

首次访问首页时,程序读取 chapter 参数。没有这个参数,就显示索引为 0 的第一章。点击目录中的章节链接后,地址会变为类似 http://127.0.0.1:8000/?chapter=1,程序据此显示第二章。

示例的章节索引从 0 开始:第一章是 0,第二章是 1。链接中输出的索引来自程序内部循环,不是读者提交的任意路径。用户输入的参数仍会经过整数验证和范围检查:无效格式或超出章节数量的值不会被用于访问数组。这能避免无效索引导致的错误,但它不是用户身份认证,也不能代替完整的访问控制。

正文容器使用 CSS 的 white-space: pre-wrap 保留换行。PHP 输出前调用 htmlspecialchars,所以正文中的尖括号会显示为文本,而不会被浏览器当成 HTML 标签执行。若你的作品正文里本来就需要呈现加粗、链接等 HTML,这个示例会把标签转义显示;不要为了“让格式生效”就删除转义。应改用可信任的内容格式和经过严格净化的输出流程。

五、把示例改成自己的作品

修改作品名和作者,直接改数组中的 title、author 值;添加章节,则在 chapters 数组里增加一组包含 title 与 content 的数据。每组之间用逗号分隔,字符串使用 UTF-8 保存。

'chapters' => [
    [
        'title' => '第一章:开端',
        'content' => <<<'TEXT'
在这里写第一章正文。
可以直接换行。
TEXT
    ],
    [
        'title' => '第二章:新的线索',
        'content' => <<<'TEXT'
在这里写第二章正文。
TEXT
    ],
],

添加章节后不需要另外设置总章节数,程序会用 count($chapters) 计算数量。目录链接、上一章和下一章按钮也会根据数组位置自动生成。若章节顺序不对,检查数组中的排列顺序;若页面报错,检查数组方括号、键名引号和逗号是否配对。

数组适合少量演示数据,但不适合频繁编辑或大量内容。如果每次更新都要修改 PHP 文件,不便于多人维护,也难以提供草稿、权限、搜索等功能。扩展到这类需求时,通常会把作品与章节存进数据库,并使用参数化查询读取数据。数据库解决的是数据保存和查询问题,并不会自动解决登录授权、内容审核或输出安全问题。

六、参数限制与安全用途说明

本示例只接受可验证为整数的 chapter 参数,并要求它落在 0 到章节总数减一的范围内。它没有对外开放文件路径,也没有把用户输入拼接进 include、文件读取路径或 SQL 语句。不要为了从文件读取章节,就直接写成 file_get_contents($_GET['file']);这类写法会把用户输入变成文件访问目标,可能引发目录穿越或读取不应公开的文件。

HTML 转义的作用也有边界:它降低了把普通文本输出到 HTML 页面时发生脚本注入的风险,但前提是使用在正确的输出位置。HTML 文本节点、HTML 属性、JavaScript、CSS 和 URL 的编码规则并不相同,不能认为一次 htmlspecialchars 就适用于所有上下文。示例把动态标题和正文放在 HTML 文本节点中,因此采用 HTML 转义;没有把作品内容拼进脚本或样式。

示例中的 filter_input 只做整数格式验证,范围检查由后续条件完成。它不是防爬虫、防拒绝服务或防滥用机制;公开部署时仍要根据服务需求设置请求限制、日志、备份和内容访问策略。本文也没有加入身份验证,因此页面中的作品默认对任何能访问网站的人可见。不要把未公开、敏感或受访问权限限制的内容直接放入公开页面。

作品文字的版权和发布许可需要由内容提供者自行确认。代码只负责展示,并不判断文字是否有权发布,也不提供自动授权或版权保护。若作品面向公众发布,还需按实际情况处理署名、授权、隐私和平台规则。

七、常见错误排查

  • 浏览器显示 PHP 源码。说明文件没有经过 PHP 解释器处理。确认文件名是 index.php,并通过 PHP 开发服务器或配置好的 Web 服务器访问;不要双击文件用浏览器直接打开。
  • 出现“命令找不到”。检查 PHP 是否安装,以及终端是否能找到 PHP 可执行文件。php -v 若无法运行,先修复环境,页面代码还没有机会执行。
  • 提示章节不存在。确认地址参数是有效整数,并且小于章节数。示例从 0 开始编号;把第二章写成 ?chapter=2,在只有两章时会超出范围。
  • 中文乱码。确认 PHP 文件保存为 UTF-8,页面包含 meta charset="utf-8",并在转义函数中指定 UTF-8。不要在编辑器里把文件保存成与页面编码不一致的格式。
  • 正文换行消失。确认正文在 HTML 中放在带有 white-space: pre-wrap 的容器内。若替换了样式或容器,浏览器可能按普通 HTML 空白规则合并换行。
  • 改完代码出现解析错误。检查 nowdoc 结束标记、方括号、逗号和分号。PHP 语法错误通常会在服务器端显示行号;开发环境可以据此检查附近代码,上线环境则不应向访客公开详细错误信息。
  • 标题里输入尖括号后显示成实体。这是转义的预期结果,页面会把输入当作文字,而不是执行它。不要为了让标签生效而直接输出未经处理的用户内容。

八、完成第一部作品后的下一步

先确认这三个动作都能工作:打开首页看到作品信息;点击目录能切换章节;最后一章没有“下一章”,第一章没有“上一章”。然后再逐步增加章节、调整字体和版面。一次只改一个部分,出错时更容易判断原因。

如果只是展示固定文本,这个单文件示例就足以说明 PHP 阅读页的基本结构:准备数据、验证请求参数、选择章节、转义动态内容,再输出 HTML。若要让非开发者编辑作品、管理多个用户或保存阅读进度,就已经超出这个入门示例的范围,需要进一步设计数据存储、权限和部署方案。明确这些边界,再决定是否扩展,比把所有功能塞进一个页面更稳妥。

© 版权声明

相关文章