Use content negotation to serve acceptable content types for web browsers viewing OPDS/RSS/Atom feeds

This commit is contained in:
Alex Cabal 2023-06-20 14:30:05 -05:00
parent 558979ecd9
commit 76cf0d296a
8 changed files with 230 additions and 152 deletions

View file

@ -8,13 +8,14 @@
"files": ["lib/Constants.php", "lib/CoreFunctions.php"] "files": ["lib/Constants.php", "lib/CoreFunctions.php"]
}, },
"platform":{ "platform":{
"php": "7.2.24" "php": "8.1.2"
}, },
"require": { "require": {
"thecodingmachine/safe": "^1.3.3", "thecodingmachine/safe": "^1.3.3",
"phpmailer/phpmailer": "^6.6.0", "phpmailer/phpmailer": "^6.6.0",
"ramsey/uuid": "4.2.3", "ramsey/uuid": "4.2.3",
"gregwar/captcha": "^1.1.9", "gregwar/captcha": "^1.1.9",
"php-webdriver/webdriver": "^1.12.1" "php-webdriver/webdriver": "^1.12.1",
"pear/http2": "^2.0.0"
} }
} }

271
composer.lock generated
View file

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"content-hash": "0a100c86bc1d94d7883ed56c9e3304fa", "content-hash": "c3a2ec797ba64706306394cca97dd37e",
"packages": [ "packages": [
{ {
"name": "brick/math", "name": "brick/math",
@ -50,6 +50,10 @@
"brick", "brick",
"math" "math"
], ],
"support": {
"issues": "https://github.com/brick/math/issues",
"source": "https://github.com/brick/math/tree/0.9.3"
},
"funding": [ "funding": [
{ {
"url": "https://github.com/BenMorel", "url": "https://github.com/BenMorel",
@ -64,16 +68,16 @@
}, },
{ {
"name": "gregwar/captcha", "name": "gregwar/captcha",
"version": "v1.1.9", "version": "v1.2.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/Gregwar/Captcha.git", "url": "https://github.com/Gregwar/Captcha.git",
"reference": "4bb668e6b40e3205a020ca5ee4ca8cff8b8780c5" "reference": "6e5b61b66ac89885b505153f4ef9a74ffa5b3074"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/Gregwar/Captcha/zipball/4bb668e6b40e3205a020ca5ee4ca8cff8b8780c5", "url": "https://api.github.com/repos/Gregwar/Captcha/zipball/6e5b61b66ac89885b505153f4ef9a74ffa5b3074",
"reference": "4bb668e6b40e3205a020ca5ee4ca8cff8b8780c5", "reference": "6e5b61b66ac89885b505153f4ef9a74ffa5b3074",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -85,7 +89,7 @@
"require-dev": { "require-dev": {
"phpunit/phpunit": "^6.4" "phpunit/phpunit": "^6.4"
}, },
"type": "captcha", "type": "library",
"autoload": { "autoload": {
"psr-4": { "psr-4": {
"Gregwar\\": "src/Gregwar" "Gregwar\\": "src/Gregwar"
@ -113,41 +117,93 @@
"captcha", "captcha",
"spam" "spam"
], ],
"time": "2020-03-24T14:39:05+00:00" "support": {
"issues": "https://github.com/Gregwar/Captcha/issues",
"source": "https://github.com/Gregwar/Captcha/tree/v1.2.0"
},
"time": "2023-03-24T22:12:41+00:00"
}, },
{ {
"name": "php-webdriver/webdriver", "name": "pear/http2",
"version": "1.13.1", "version": "v2.0.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/php-webdriver/php-webdriver.git", "url": "https://github.com/pear/HTTP2.git",
"reference": "6dfe5f814b796c1b5748850aa19f781b9274c36c" "reference": "72e15b4faa86f6109c6fc3aa82c5515b6453b3b5"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/php-webdriver/php-webdriver/zipball/6dfe5f814b796c1b5748850aa19f781b9274c36c", "url": "https://api.github.com/repos/pear/HTTP2/zipball/72e15b4faa86f6109c6fc3aa82c5515b6453b3b5",
"reference": "6dfe5f814b796c1b5748850aa19f781b9274c36c", "reference": "72e15b4faa86f6109c6fc3aa82c5515b6453b3b5",
"shasum": ""
},
"require-dev": {
"phpunit/phpunit": "^9"
},
"type": "library",
"autoload": {
"psr-0": {
"HTTP2": "./"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-2-Clause"
],
"authors": [
{
"name": "Michael Wallner",
"email": "mike@php.net",
"role": "Lead"
},
{
"name": "Philippe Jausions",
"email": "jausions@php.net",
"role": "Lead"
}
],
"description": "Miscellaneous HTTP utilities",
"homepage": "http://pear.php.net/package/HTTP2",
"support": {
"issues": "http://pear.php.net/bugs/search.php?cmd=display&package_name[]=HTTP2",
"source": "https://github.com/pear/HTTP2"
},
"time": "2023-03-22T20:22:11+00:00"
},
{
"name": "php-webdriver/webdriver",
"version": "1.14.0",
"source": {
"type": "git",
"url": "https://github.com/php-webdriver/php-webdriver.git",
"reference": "3ea4f924afb43056bf9c630509e657d951608563"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-webdriver/php-webdriver/zipball/3ea4f924afb43056bf9c630509e657d951608563",
"reference": "3ea4f924afb43056bf9c630509e657d951608563",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"ext-curl": "*", "ext-curl": "*",
"ext-json": "*", "ext-json": "*",
"ext-zip": "*", "ext-zip": "*",
"php": "^5.6 || ~7.0 || ^8.0", "php": "^7.3 || ^8.0",
"symfony/polyfill-mbstring": "^1.12", "symfony/polyfill-mbstring": "^1.12",
"symfony/process": "^2.8 || ^3.1 || ^4.0 || ^5.0 || ^6.0" "symfony/process": "^5.0 || ^6.0"
}, },
"replace": { "replace": {
"facebook/webdriver": "*" "facebook/webdriver": "*"
}, },
"require-dev": { "require-dev": {
"ondram/ci-detector": "^2.1 || ^3.5 || ^4.0", "ergebnis/composer-normalize": "^2.20.0",
"ondram/ci-detector": "^4.0",
"php-coveralls/php-coveralls": "^2.4", "php-coveralls/php-coveralls": "^2.4",
"php-mock/php-mock-phpunit": "^1.1 || ^2.0", "php-mock/php-mock-phpunit": "^2.0",
"php-parallel-lint/php-parallel-lint": "^1.2", "php-parallel-lint/php-parallel-lint": "^1.2",
"phpunit/phpunit": "^5.7 || ^7 || ^8 || ^9", "phpunit/phpunit": "^9.3",
"squizlabs/php_codesniffer": "^3.5", "squizlabs/php_codesniffer": "^3.5",
"symfony/var-dumper": "^3.3 || ^4.0 || ^5.0 || ^6.0" "symfony/var-dumper": "^5.0 || ^6.0"
}, },
"suggest": { "suggest": {
"ext-SimpleXML": "For Firefox profile creation" "ext-SimpleXML": "For Firefox profile creation"
@ -174,20 +230,24 @@
"selenium", "selenium",
"webdriver" "webdriver"
], ],
"time": "2022-10-11T11:49:44+00:00" "support": {
"issues": "https://github.com/php-webdriver/php-webdriver/issues",
"source": "https://github.com/php-webdriver/php-webdriver/tree/1.14.0"
},
"time": "2023-02-09T12:12:19+00:00"
}, },
{ {
"name": "phpmailer/phpmailer", "name": "phpmailer/phpmailer",
"version": "v6.7.1", "version": "v6.8.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/PHPMailer/PHPMailer.git", "url": "https://github.com/PHPMailer/PHPMailer.git",
"reference": "49cd7ea3d2563f028d7811f06864a53b1f15ff55" "reference": "df16b615e371d81fb79e506277faea67a1be18f1"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/49cd7ea3d2563f028d7811f06864a53b1f15ff55", "url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/df16b615e371d81fb79e506277faea67a1be18f1",
"reference": "49cd7ea3d2563f028d7811f06864a53b1f15ff55", "reference": "df16b615e371d81fb79e506277faea67a1be18f1",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -244,26 +304,30 @@
} }
], ],
"description": "PHPMailer is a full-featured email creation and transfer class for PHP", "description": "PHPMailer is a full-featured email creation and transfer class for PHP",
"support": {
"issues": "https://github.com/PHPMailer/PHPMailer/issues",
"source": "https://github.com/PHPMailer/PHPMailer/tree/v6.8.0"
},
"funding": [ "funding": [
{ {
"url": "https://github.com/Synchro", "url": "https://github.com/Synchro",
"type": "github" "type": "github"
} }
], ],
"time": "2022-12-08T13:30:06+00:00" "time": "2023-03-06T14:43:22+00:00"
}, },
{ {
"name": "ramsey/collection", "name": "ramsey/collection",
"version": "1.2.2", "version": "1.3.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/ramsey/collection.git", "url": "https://github.com/ramsey/collection.git",
"reference": "cccc74ee5e328031b15640b51056ee8d3bb66c0a" "reference": "ad7475d1c9e70b190ecffc58f2d989416af339b4"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/ramsey/collection/zipball/cccc74ee5e328031b15640b51056ee8d3bb66c0a", "url": "https://api.github.com/repos/ramsey/collection/zipball/ad7475d1c9e70b190ecffc58f2d989416af339b4",
"reference": "cccc74ee5e328031b15640b51056ee8d3bb66c0a", "reference": "ad7475d1c9e70b190ecffc58f2d989416af339b4",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -326,6 +390,10 @@
"queue", "queue",
"set" "set"
], ],
"support": {
"issues": "https://github.com/ramsey/collection/issues",
"source": "https://github.com/ramsey/collection/tree/1.3.0"
},
"funding": [ "funding": [
{ {
"url": "https://github.com/ramsey", "url": "https://github.com/ramsey",
@ -356,7 +424,7 @@
"brick/math": "^0.8 || ^0.9", "brick/math": "^0.8 || ^0.9",
"ext-json": "*", "ext-json": "*",
"php": "^7.2 || ^8.0", "php": "^7.2 || ^8.0",
"ramsey/collection": "1.2.2", "ramsey/collection": "^1.0",
"symfony/polyfill-ctype": "^1.8", "symfony/polyfill-ctype": "^1.8",
"symfony/polyfill-php80": "^1.14" "symfony/polyfill-php80": "^1.14"
}, },
@ -420,6 +488,10 @@
"identifier", "identifier",
"uuid" "uuid"
], ],
"support": {
"issues": "https://github.com/ramsey/uuid/issues",
"source": "https://github.com/ramsey/uuid/tree/4.2.3"
},
"funding": [ "funding": [
{ {
"url": "https://github.com/ramsey", "url": "https://github.com/ramsey",
@ -432,88 +504,25 @@
], ],
"time": "2021-09-25T23:10:38+00:00" "time": "2021-09-25T23:10:38+00:00"
}, },
{
"name": "symfony/deprecation-contracts",
"version": "v2.5.2",
"source": {
"type": "git",
"url": "https://github.com/symfony/deprecation-contracts.git",
"reference": "e8b495ea28c1d97b5e0c121748d6f9b53d075c66"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/e8b495ea28c1d97b5e0c121748d6f9b53d075c66",
"reference": "e8b495ea28c1d97b5e0c121748d6f9b53d075c66",
"shasum": ""
},
"require": {
"php": ">=7.1"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "2.5-dev"
},
"thanks": {
"name": "symfony/contracts",
"url": "https://github.com/symfony/contracts"
}
},
"autoload": {
"files": [
"function.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "A generic function and convention to trigger deprecation notices",
"homepage": "https://symfony.com",
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2022-01-02T09:53:40+00:00"
},
{ {
"name": "symfony/finder", "name": "symfony/finder",
"version": "v5.4.19", "version": "v6.3.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/finder.git", "url": "https://github.com/symfony/finder.git",
"reference": "6071aebf810ad13fe8200c224f36103abb37cf1f" "reference": "d9b01ba073c44cef617c7907ce2419f8d00d75e2"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/finder/zipball/6071aebf810ad13fe8200c224f36103abb37cf1f", "url": "https://api.github.com/repos/symfony/finder/zipball/d9b01ba073c44cef617c7907ce2419f8d00d75e2",
"reference": "6071aebf810ad13fe8200c224f36103abb37cf1f", "reference": "d9b01ba073c44cef617c7907ce2419f8d00d75e2",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"php": ">=7.2.5", "php": ">=8.1"
"symfony/deprecation-contracts": "^2.1|^3", },
"symfony/polyfill-php80": "^1.16" "require-dev": {
"symfony/filesystem": "^6.0"
}, },
"type": "library", "type": "library",
"autoload": { "autoload": {
@ -540,6 +549,9 @@
], ],
"description": "Finds files and directories via an intuitive fluent interface", "description": "Finds files and directories via an intuitive fluent interface",
"homepage": "https://symfony.com", "homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/finder/tree/v6.3.0"
},
"funding": [ "funding": [
{ {
"url": "https://symfony.com/sponsor", "url": "https://symfony.com/sponsor",
@ -554,7 +566,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2023-01-14T19:14:44+00:00" "time": "2023-04-02T01:25:41+00:00"
}, },
{ {
"name": "symfony/polyfill-ctype", "name": "symfony/polyfill-ctype",
@ -619,6 +631,9 @@
"polyfill", "polyfill",
"portable" "portable"
], ],
"support": {
"source": "https://github.com/symfony/polyfill-ctype/tree/v1.27.0"
},
"funding": [ "funding": [
{ {
"url": "https://symfony.com/sponsor", "url": "https://symfony.com/sponsor",
@ -699,6 +714,9 @@
"portable", "portable",
"shim" "shim"
], ],
"support": {
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.27.0"
},
"funding": [ "funding": [
{ {
"url": "https://symfony.com/sponsor", "url": "https://symfony.com/sponsor",
@ -779,6 +797,9 @@
"portable", "portable",
"shim" "shim"
], ],
"support": {
"source": "https://github.com/symfony/polyfill-php80/tree/v1.27.0"
},
"funding": [ "funding": [
{ {
"url": "https://symfony.com/sponsor", "url": "https://symfony.com/sponsor",
@ -855,6 +876,9 @@
"portable", "portable",
"shim" "shim"
], ],
"support": {
"source": "https://github.com/symfony/polyfill-php81/tree/v1.27.0"
},
"funding": [ "funding": [
{ {
"url": "https://symfony.com/sponsor", "url": "https://symfony.com/sponsor",
@ -873,21 +897,20 @@
}, },
{ {
"name": "symfony/process", "name": "symfony/process",
"version": "v5.4.19", "version": "v6.3.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/process.git", "url": "https://github.com/symfony/process.git",
"reference": "c5ba874c9b636dbccf761e22ce750e88ec3f55e1" "reference": "8741e3ed7fe2e91ec099e02446fb86667a0f1628"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/process/zipball/c5ba874c9b636dbccf761e22ce750e88ec3f55e1", "url": "https://api.github.com/repos/symfony/process/zipball/8741e3ed7fe2e91ec099e02446fb86667a0f1628",
"reference": "c5ba874c9b636dbccf761e22ce750e88ec3f55e1", "reference": "8741e3ed7fe2e91ec099e02446fb86667a0f1628",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"php": ">=7.2.5", "php": ">=8.1"
"symfony/polyfill-php80": "^1.16"
}, },
"type": "library", "type": "library",
"autoload": { "autoload": {
@ -914,6 +937,9 @@
], ],
"description": "Executes commands in sub-processes", "description": "Executes commands in sub-processes",
"homepage": "https://symfony.com", "homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/process/tree/v6.3.0"
},
"funding": [ "funding": [
{ {
"url": "https://symfony.com/sponsor", "url": "https://symfony.com/sponsor",
@ -928,7 +954,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2023-01-01T08:32:19+00:00" "time": "2023-05-19T08:06:44+00:00"
}, },
{ {
"name": "thecodingmachine/safe", "name": "thecodingmachine/safe",
@ -1063,22 +1089,26 @@
"MIT" "MIT"
], ],
"description": "PHP core functions that throw exceptions instead of returning FALSE on error", "description": "PHP core functions that throw exceptions instead of returning FALSE on error",
"support": {
"issues": "https://github.com/thecodingmachine/safe/issues",
"source": "https://github.com/thecodingmachine/safe/tree/v1.3.3"
},
"time": "2020-10-28T17:51:34+00:00" "time": "2020-10-28T17:51:34+00:00"
} }
], ],
"packages-dev": [ "packages-dev": [
{ {
"name": "phpstan/phpstan", "name": "phpstan/phpstan",
"version": "1.9.14", "version": "1.10.20",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/phpstan/phpstan.git", "url": "https://github.com/phpstan/phpstan.git",
"reference": "e5fcc96289cf737304286a9b505fbed091f02e58" "reference": "c4c8adb56313fbd59ff5a5f4a496bbed1a6b8803"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/e5fcc96289cf737304286a9b505fbed091f02e58", "url": "https://api.github.com/repos/phpstan/phpstan/zipball/c4c8adb56313fbd59ff5a5f4a496bbed1a6b8803",
"reference": "e5fcc96289cf737304286a9b505fbed091f02e58", "reference": "c4c8adb56313fbd59ff5a5f4a496bbed1a6b8803",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -1106,6 +1136,13 @@
"dev", "dev",
"static analysis" "static analysis"
], ],
"support": {
"docs": "https://phpstan.org/user-guide/getting-started",
"forum": "https://github.com/phpstan/phpstan/discussions",
"issues": "https://github.com/phpstan/phpstan/issues",
"security": "https://github.com/phpstan/phpstan/security/policy",
"source": "https://github.com/phpstan/phpstan-src"
},
"funding": [ "funding": [
{ {
"url": "https://github.com/ondrejmirtes", "url": "https://github.com/ondrejmirtes",
@ -1120,7 +1157,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2023-01-19T10:47:09+00:00" "time": "2023-06-20T12:07:40+00:00"
}, },
{ {
"name": "thecodingmachine/phpstan-safe-rule", "name": "thecodingmachine/phpstan-safe-rule",
@ -1173,6 +1210,10 @@
} }
], ],
"description": "A PHPStan rule to detect safety issues. Must be used in conjunction with thecodingmachine/safe", "description": "A PHPStan rule to detect safety issues. Must be used in conjunction with thecodingmachine/safe",
"support": {
"issues": "https://github.com/thecodingmachine/phpstan-safe-rule/issues",
"source": "https://github.com/thecodingmachine/phpstan-safe-rule/tree/v1.2.0"
},
"time": "2022-01-17T10:12:29+00:00" "time": "2022-01-17T10:12:29+00:00"
} }
], ],
@ -1183,5 +1224,5 @@
"prefer-lowest": false, "prefer-lowest": false,
"platform": [], "platform": [],
"platform-dev": [], "platform-dev": [],
"plugin-api-version": "1.1.0" "plugin-api-version": "2.3.0"
} }

View file

@ -309,14 +309,4 @@ Define webroot /standardebooks.org/web
XSendFile on XSendFile on
XSendFilePath /standardebooks.org/web/www/feeds XSendFilePath /standardebooks.org/web/www/feeds
</DirectoryMatch> </DirectoryMatch>
# Emit content-types for RSS/Atom feeds
<DirectoryMatch "^${webroot}/www/feeds/(?<feedtype>rss|atom)/.+">
# Note the trailing e is required to complete the environmental variable reference
Header set Content-Type "application/%{MATCH_FEEDTYPE}e+xml; charset=utf-8"
<FilesMatch "^index\.php$">
Header set Content-Type "application/xhtml+xml; charset=utf-8"
</FilesMatch>
</DirectoryMatch>
</VirtualHost> </VirtualHost>

View file

@ -291,14 +291,4 @@ Define webroot /standardebooks.org/web
XSendFile on XSendFile on
XSendFilePath /standardebooks.org/web/www/feeds XSendFilePath /standardebooks.org/web/www/feeds
</DirectoryMatch> </DirectoryMatch>
# Emit content-types for RSS/Atom feeds
<DirectoryMatch "^${webroot}/www/feeds/(?<feedtype>rss|atom)/.+">
# Note the trailing e is required to complete the environmental variable reference
Header set Content-Type "application/%{MATCH_FEEDTYPE}e+xml; charset=utf-8"
<FilesMatch "^index\.php$">
Header set Content-Type "application/xhtml+xml; charset=utf-8"
</FilesMatch>
</DirectoryMatch>
</VirtualHost> </VirtualHost>

View file

@ -1,8 +1,17 @@
<? <?
require_once('Core.php'); require_once('Core.php');
// `text/xsl` is the only mime type recognized by Chrome for XSL stylesheets $http = new HTTP2();
header('Content-Type: text/xsl; charset=utf-8');
$contentType = [
'application/xslt+xml',
'application/xml',
'text/xml'
];
$mime = $http->negotiateMimeType($contentType, 'application/xslt+xml');
header('Content-Type: ' . $mime . '; charset=utf-8');
print("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n") print("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n")
?> ?>
<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/"> <xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/">
@ -19,7 +28,7 @@ print("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n")
</xsl:otherwise> </xsl:otherwise>
</xsl:choose> </xsl:choose>
<p><xsl:value-of select="/atom:feed/atom:subtitle"/></p> <p><xsl:value-of select="/atom:feed/atom:subtitle"/></p>
<p>This page is an Atom 1.0 feed. The URL in your browsers address bar (<a class="url"><xsl:attribute name="href"><xsl:value-of select="/atom:feed/atom:link[@rel='self']/@href"/></xsl:attribute><xsl:value-of select="/atom:feed/atom:link[@rel='self']/@href"/></a>) can be used in any Atom client.</p> <p>This page is an Atom 1.0 feed. The URL in your browsers address bar (<a class="url"><xsl:attribute name="href"><xsl:value-of select="/atom:feed/atom:link[@rel='self']/@href"/></xsl:attribute><xsl:value-of select="/atom:feed/atom:link[@rel='self']/@href"/></a>) can be used in any Atom client. If youre prompted to authenticate, enter the email address you used to join the <a href="https://standardebooks.org/donate#patrons-circle">Patrons Circle</a> and a blank password.</p>
<ol class="ebooks-list list"> <ol class="ebooks-list list">
<xsl:for-each select="/atom:feed/atom:entry"> <xsl:for-each select="/atom:feed/atom:entry">
<li> <li>

View file

@ -54,20 +54,49 @@ try{
// Much more efficient than reading it in PHP and outputting it that way. // Much more efficient than reading it in PHP and outputting it that way.
header('X-Sendfile: ' . WEB_ROOT . $path); header('X-Sendfile: ' . WEB_ROOT . $path);
if(preg_match('/^\/feeds\/opds/', $path)){ $http = new HTTP2();
header('Content-Type: application/atom+xml;profile=opds-catalog;kind=acquisition; charset=utf-8'); $mime = 'application/xml';
if(preg_match('/\/index\.xml$/', $path)){ // Decide on what content-type to serve via HTTP content negotation.
header('Content-Type: application/atom+xml;profile=opds-catalog;kind=navigation; charset=utf-8'); // If the feed is viewed from a web browser, we will usuall serve application/xml as that's typically what's in the browser's Accept header.
// If the Accept header has application/rss+xml or application/atom+xml then serve that instead, as those are the
// "technically correct" content types that may be requested by RSS readers.
if(preg_match('/^\/feeds\/opds/', $path)){
$contentType = [
'application/atom+xml',
'application/xml',
'text/xml'
];
$mime = $http->negotiateMimeType($contentType, 'application/atom+xml');
if($mime == 'application/atom+xml'){
if(preg_match('/\/index\.xml$/', $path)){
$mime .= ';profile=opds-catalog;kind=navigation; charset=utf-8';
}
else{
$mime .= ';profile=opds-catalog;kind=acquisition; charset=utf-8';
}
} }
} }
elseif(preg_match('/^\/feeds\/rss/', $path)){ elseif(preg_match('/^\/feeds\/rss/', $path)){
header('Content-Type: application/rss+xml'); $contentType = [
'application/rss+xml',
'application/xml',
'text/xml'
];
$mime = $http->negotiateMimeType($contentType, 'application/rss+xml');
} }
elseif(preg_match('/^\/feeds\/atom/', $path)){ elseif(preg_match('/^\/feeds\/atom/', $path)){
header('Content-Type: application/atom+xml'); $contentType = [
'application/atom+xml',
'application/xml',
'text/xml'
];
$mime = $http->negotiateMimeType($contentType, 'application/atom+xml');
} }
header('Content-Type: ' . $mime);
exit(); exit();
} }
catch(Exceptions\LoginRequiredException){ catch(Exceptions\LoginRequiredException){

View file

@ -1,8 +1,17 @@
<? <?
require_once('Core.php'); require_once('Core.php');
// `text/xsl` is the only mime type recognized by Chrome for XSL stylesheets $http = new HTTP2();
header('Content-Type: text/xsl; charset=utf-8');
$contentType = [
'application/xslt+xml',
'application/xml',
'text/xml'
];
$mime = $http->negotiateMimeType($contentType, 'application/xslt+xml');
header('Content-Type: ' . $mime . '; charset=utf-8');
print("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n") print("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n")
?> ?>
<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:atom="http://www.w3.org/2005/Atom"> <xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:atom="http://www.w3.org/2005/Atom">
@ -19,7 +28,7 @@ print("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n")
</xsl:otherwise> </xsl:otherwise>
</xsl:choose> </xsl:choose>
<p><xsl:value-of select="/atom:feed/atom:subtitle"/></p> <p><xsl:value-of select="/atom:feed/atom:subtitle"/></p>
<p>This page is an OPDS 1.2 feed. The URL in your browsers address bar (<a class="url"><xsl:attribute name="href"><xsl:value-of select="/atom:feed/atom:link[@rel='self']/@href"/></xsl:attribute><xsl:value-of select="/atom:feed/atom:link[@rel='self']/@href"/></a>) can be used in any OPDS client.</p> <p>This page is an OPDS 1.2 feed. The URL in your browsers address bar (<a class="url"><xsl:attribute name="href"><xsl:value-of select="/atom:feed/atom:link[@rel='self']/@href"/></xsl:attribute><xsl:value-of select="/atom:feed/atom:link[@rel='self']/@href"/></a>) can be used in any OPDS client. If youre prompted to authenticate, enter the email address you used to join the <a href="https://standardebooks.org/donate#patrons-circle">Patrons Circle</a> and a blank password.</p>
<xsl:if test="/atom:feed/atom:entry[./atom:link[starts-with(@type, 'application/atom+xml;profile=opds-catalog;kind=')]]"> <xsl:if test="/atom:feed/atom:entry[./atom:link[starts-with(@type, 'application/atom+xml;profile=opds-catalog;kind=')]]">
<ol class="rss"> <ol class="rss">
<xsl:for-each select="/atom:feed/atom:entry[./atom:link[starts-with(@type, 'application/atom+xml;profile=opds-catalog;kind=')]]"> <xsl:for-each select="/atom:feed/atom:entry[./atom:link[starts-with(@type, 'application/atom+xml;profile=opds-catalog;kind=')]]">

View file

@ -1,8 +1,17 @@
<? <?
require_once('Core.php'); require_once('Core.php');
// `text/xsl` is the only mime type recognized by Chrome for XSL stylesheets $http = new HTTP2();
header('Content-Type: text/xsl; charset=utf-8');
$contentType = [
'application/xslt+xml',
'application/xml',
'text/xml'
];
$mime = $http->negotiateMimeType($contentType, 'application/xslt+xml');
header('Content-Type: ' . $mime . '; charset=utf-8');
print("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n") print("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n")
?> ?>
<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/"> <xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/">
@ -19,7 +28,7 @@ print("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n")
</xsl:otherwise> </xsl:otherwise>
</xsl:choose> </xsl:choose>
<p><xsl:value-of select="/rss/channel/description"/></p> <p><xsl:value-of select="/rss/channel/description"/></p>
<p>This page is an RSS 2.0 feed. The URL in your browsers address bar (<a class="url"><xsl:attribute name="href"><xsl:value-of select="/rss/channel/atom:link/@href"/></xsl:attribute><xsl:value-of select="/rss/channel/atom:link/@href"/></a>) can be used in any RSS reader.</p> <p>This page is an RSS 2.0 feed. The URL in your browsers address bar (<a class="url"><xsl:attribute name="href"><xsl:value-of select="/rss/channel/atom:link/@href"/></xsl:attribute><xsl:value-of select="/rss/channel/atom:link/@href"/></a>) can be used in any RSS reader. If youre prompted to authenticate, enter the email address you used to join the <a href="https://standardebooks.org/donate#patrons-circle">Patrons Circle</a> and a blank password.</p>
<ol class="ebooks-list list rss"> <ol class="ebooks-list list rss">
<xsl:for-each select="/rss/channel/item"> <xsl:for-each select="/rss/channel/item">
<li> <li>