wyz / file-indexer
一些用于处理文件和将文件属性索引到数据库中的PHP类。
Requires
- psr/log: ^1.1
Requires (Dev)
- ext-pdo: *
- phpunit/phpunit: ^8
- squizlabs/php_codesniffer: ^3.5
This package is not auto-updated.
Last update: 2024-09-17 08:52:35 UTC
README
PathProcessor是您的PHP应用程序的基类,允许递归遍历文件和子目录,并对它们执行操作。PathProcessor中的操作是'无'(因为其processFile()定义是空的),可以由子类定义。
查看PathProcessor和SubpathProcessor的代码,并查看PathRemover的简单示例。有关几个配置设置(如是否也处理符号链接或相对文件名的'基础目录'),请参阅构造函数。
FileIndexer是一个更详细的示例,它在数据库表中'索引'一些文件属性。它可以进一步子类化以在'索引'部分执行一些有趣的操作;默认情况下,它只读取文件并在数据库行中存储一个哈希值。
(因此,为了完整性:这里的'索引'并不意味着文件内容的文本索引。它可能,但需要作为FileIndexer的新子类来编写。)
FileIndexer有什么有趣之处?
这听起来可能像是已经编写了这段代码,可以节省几个小时的时间,但除此之外,并不是非常引人注目。
有趣之处在于不区分大小写的文件系统和数据库表的存在,以及不同数据库系统通过LIKE和CASE语句对大小写敏感性的不同处理。使用具有不同大小写敏感性的系统的需求使我非常困惑于需要检查的条件,以至于我决定编写一个可以处理文件系统和数据库大小写敏感性所有组合的类,并且已经单元测试到我可以信任它不会对存储的数据进行任何意外的操作(如最终出现重复行)。
FileIndexer将确保如果文件系统或数据库是大小写不敏感的,则不会索引两个'除了大小写外相同'的文件。这意味着
- 将不区分大小写的文件系统与区分大小写的数据库结合使用不会带来惊喜;文件将正确匹配,无论磁盘上的文件名大小写与数据库中存储的大小写是否相同。
- 将区分大小写的文件系统与不区分大小写的数据库结合使用意味着只索引其中一个文件;无法索引的文件将记录一个警告。在文件系统中重新设置已索引文件的大小写不会影响索引表;文件仍然会被识别。
注意敏感度设置
关于大小写敏感性的假设设置与其他配置设置类似。'case_insensitive_filesystem'(在PathProcessor中定义)的默认值为false;'case_insensitive_database'(在FileIndexer中定义)的默认值为true。请注意,'数据库'从技术上讲是指包含文件名数据的数据库表。
正确配置这些设置很重要,以免出现意外行为。为了参考(至少对我来说),这种意外行为可能是
如果将'case_insensitive_database'设置为false,而表实际上是大小写不敏感的:在区分大小写的文件系统上索引不同大小写的文件时出现错误(因为只能插入其中一个,而这并不是代码所假设的)。
如果将'case_insensitive_database' 未 设置为false,而表实际上是大小写敏感的
- 与区分大小写的文件系统结合使用,此类将拒绝索引不同大小写的文件。
- 与不区分大小写的文件系统结合时,在重新索引包含大写字母的文件时插入新文件记录会失败。这是因为查找数据库中现有记录的代码由于假设可以通过查询小写等效项找到文件名而遗漏了它们。(这意味着您很快就会看到错误;日志中会记录有关大小写敏感性的提示。)
如果文件系统实际上是不区分大小写的,但没有将 'case_insensitive_filesystem' 设置为 true
- 与区分大小写的数据库表结合使用时,如果用不同的大小写排列处理(即将其传递给 processPaths()),则存在为同一文件生成重复索引数据库记录的风险。
- 与不区分大小写的数据库表结合使用时,不会发生任何情况(除非代码可能假设存在独立的数据库记录,如果您执行上述操作,则可能会搞乱日志)。
如果文件系统实际上是不区分大小写的,而 'case_insensitive_filesystem' 设置为 true:如果存在具有不同大小写排列的多个文件,则只会索引其中一个。
使用 SQLite
FileIndexer 使用使用 LIKE 操作符的 SQL 查询。对于 SQLite 数据库,LIKE 操作符的大小写敏感性不由表的大小写敏感性或 SQL 语句中的关键字确定,而由连接范围设置,使用 PRAGMA 语句。当使用区分大小写的表 和 区分大小写的文件系统时,必须执行以下操作,以便代码能够处理不同大小写的文件
PRAGMA case_sensitive_like=ON;
该类不会自动执行此操作,因为它不想全局修改数据库连接;这应由调用者决定。
兼容性
代码已针对 MySQL 和 SQLite 数据库进行测试;它使用 PDO 与数据库交互。
确保数据库系统正确处理大小写敏感性超出了本代码的范围。例如:在未安装特定扩展的 SQLite 中,'LIKE' 操作无法正确匹配大小写不同的非 ASCII 字符,因此 'LIKE' 操作不是真正的不区分大小写,而本代码依赖于数据库或文件系统应该区分大小写的情况。当在目录名中使用不同大小写的非 ASCII 字符时,或者在磁盘上的目录名大小写与数据库中索引的目录名大小写不匹配时,这会导致问题。
虽然 PHP5.6 正式结束支持,但我将努力保持该代码与 PHP5 兼容,直到有真正的原因引入 PHP7 仅语言结构。但未在 PHP5 上进行测试,因为单元测试与 PHPUnit 5 不兼容。
测试
PHPUnit 测试的棘手之处在于它们需要一个区分大小写和不区分大小写的文件系统,而这些事情无法模拟。因此,GitHub 的标准 Travis 将只运行部分测试,针对一个文件系统。
要运行完整的测试,可以通过设置环境变量 TEST_DIR_CASE_SENSITIVE 和 TEST_DIR_CASE_INSENSITIVE 来定义区分大小写/不区分大小写的目录路径。两者都将默认为 /tmp;其中任何一个都会导致当实际的敏感性与预期不符时跳过测试。
要针对内存中不同于 SQLite 的数据库系统运行测试,设置环境变量 FILE_INDEXER_TEST_PDO_DSN(为任何有效的 PDO DSN)、FILE_INDEXER_TEST_PDO_USER 和 FILE_INDEXER_TEST_PDO_PASS。
设置这些环境变量可能需要使用 'php -d variables_order=EGPCS' 运行 phpunit 以获取它们的值。如果您知道更好的方法来动态定义这两个目录(任何人都可以运行完整的测试或覆盖 PDO 连接):欢迎反馈。