2 +----------------------------------------------------------------------+
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-2014 Facebook, Inc. (http://www.facebook.com) |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
17 #include "hphp/runtime/base/config.h"
19 #include <boost/algorithm/string.hpp>
20 #include <boost/algorithm/string/predicate.hpp>
23 #include "hphp/compiler/option.h"
24 #include "hphp/runtime/base/ini-setting.h"
25 #include "hphp/runtime/base/runtime-error.h"
28 ///////////////////////////////////////////////////////////////////////////////
31 * Normalizes hdf string names to their ini counterparts
33 * We have special handling for a few hdf strings such as those containing
34 * MySQL, Eval, IPv[4|6] and EnableHipHopSyntax
36 static std::string
normalize(const std::string
&name
) {
37 std::string out
= ".";
39 for (auto &c
: name
) {
40 // This is the first or last character
41 if (idx
== 0 || idx
== name
.length() - 1) {
43 } else if (!isalpha(c
)) {
44 // Any . or _ or numeral is just output with no special behavior
47 if (isupper(c
) && isupper(name
[idx
- 1 ]) && islower(name
[idx
+ 1])) {
48 // Handle something like "SSLPort", and c = "P", which will then put
49 // the underscore between the "L" and "P"
52 } else if (islower(c
) && isupper(name
[idx
+ 1])) {
53 // Handle something like "PathDebug", and c = "h", which will then put
54 // the underscore between the "h" and "D"
58 // Otherwise we just output as lower
65 // Make sure IPv6 or IPv4 are handled correctly
66 boost::replace_first(out
, "_i_pv", "_ipv");
67 boost::replace_first(out
, ".i_pv", ".ipv");
68 // urls are special too. Let's not have "ur_ls"
69 boost::replace_first(out
, "_ur_ls", "_urls");
70 boost::replace_first(out
, ".ur_ls", ".urls");
71 // No use of Eval in our ini strings
72 boost::replace_first(out
, ".eval.", ".");
73 boost::replace_first(out
, ".my_sql.", ".mysql.");
74 boost::replace_first(out
, ".enable_hip_hop_syntax", ".force_hh");
79 std::string
Config::IniName(const Hdf
& config
) {
80 return Config::IniName(config
.getFullPath());
83 std::string
Config::IniName(const std::string config
) {
84 return "hhvm" + normalize(config
);
87 void Config::ParseIniString(const std::string iniStr
, IniSetting::Map
&ini
) {
88 Config::SetParsedIni(ini
, iniStr
, "", false);
91 void Config::ParseHdfString(const std::string hdfStr
, Hdf
&hdf
,
92 IniSetting::Map
&ini
) {
93 hdf
.fromString(hdfStr
.c_str());
94 // Make sure we update any provided `-v` option with
95 // an equivalent change to an ini setting, if it
96 // existed already. This way a call in IniSetting::Get
97 // such as ResetSystemDefault(name) has the correct
99 std::string cname
= Config::IniName(hdf
.getLastFullName());
100 std::string cval
= hdf
.getLastValue();
101 Config::ParseIniString(cname
+ "=" + cval
, ini
);
104 void Config::ParseConfigFile(const std::string
&filename
, IniSetting::Map
&ini
,
106 // We don't allow a filename of just ".ini"
107 if (boost::ends_with(filename
, ".ini") && filename
.length() > 4) {
108 Config::ParseIniFile(filename
, ini
);
109 } else if (boost::ends_with(filename
, ".hdf") && filename
.length() > 4) {
110 Config::ParseHdfFile(filename
, hdf
);
112 raise_warning("Config files should end with .ini or .hdf. Parsing as .hdf");
113 Config::ParseHdfFile(filename
, hdf
);
117 void Config::ParseIniFile(const std::string
&filename
) {
118 IniSetting::Map nul
= nullptr;
119 Config::ParseIniFile(filename
, nul
, false);
122 void Config::ParseIniFile(const std::string
&filename
, IniSetting::Map
&ini
,
123 const bool constants_only
/* = false */) {
124 std::ifstream
ifs(filename
);
125 const std::string
str((std::istreambuf_iterator
<char>(ifs
)),
126 std::istreambuf_iterator
<char>());
127 Config::SetParsedIni(ini
, str
, filename
, constants_only
);
130 void Config::ParseHdfFile(const std::string
&filename
, Hdf
&hdf
) {
131 hdf
.append(filename
);
134 void Config::SetParsedIni(IniSetting::Map
&ini
, const std::string confStr
,
135 const std::string filename
, bool constants_only
) {
136 auto parsed_ini
= IniSetting::FromStringAsMap(confStr
, filename
);
137 for (auto &pair
: parsed_ini
.items()) {
139 ini
[pair
.first
] = pair
.second
;
141 if (constants_only
) {
142 IniSetting::FillInConstant(pair
.first
.data(), pair
.second
,
143 IniSetting::FollyDynamic());
145 IniSetting::Set(pair
.first
.data(), pair
.second
,
146 IniSetting::FollyDynamic());
151 const char* Config::Get(const IniSetting::Map
&ini
, const Hdf
& config
,
152 const char *defValue
/* = nullptr */) {
153 auto* value
= ini
.get_ptr(IniName(config
));
154 if (value
&& value
->isString()) {
155 return value
->data();
157 return config
.configGet(defValue
);
160 #define CONFIG_BODY(T, METHOD) \
161 T Config::Get##METHOD(const IniSetting::Map &ini, const Hdf& config, \
162 const T defValue /* = 0ish */) { \
163 auto* value = ini.get_ptr(IniName(config)); \
164 if (value && value->isString()) { \
166 ini_on_update(value->data(), ret); \
167 /* The HDF still wins because the -v options
168 * are still done via HDF, for now */ \
169 return config.configGet##METHOD(ret); \
171 return config.configGet##METHOD(defValue); \
173 void Config::Bind(T& loc, const IniSetting::Map &ini, const Hdf& config, \
174 const T defValue /* = 0ish */) { \
175 loc = Get##METHOD(ini, config, defValue); \
176 IniSetting::Bind(IniSetting::CORE, IniSetting::PHP_INI_SYSTEM, \
177 IniName(config), &loc); \
179 void Config::Bind(T& loc, const IniSetting::Map &ini, std::string name, \
180 const T defValue /* = 0ish */) { \
181 auto* value = ini.get_ptr(name); \
182 if (value && value->isString()) { \
183 ini_on_update(value->data(), loc); \
187 IniSetting::Bind(IniSetting::CORE, IniSetting::PHP_INI_SYSTEM, \
191 CONFIG_BODY(bool, Bool
)
192 CONFIG_BODY(char, Byte
)
193 CONFIG_BODY(unsigned char, UByte
)
194 CONFIG_BODY(int16_t, Int16
)
195 CONFIG_BODY(uint16_t, UInt16
)
196 CONFIG_BODY(int32_t, Int32
)
197 CONFIG_BODY(uint32_t, UInt32
)
198 CONFIG_BODY(int64_t, Int64
)
199 CONFIG_BODY(uint64_t, UInt64
)
200 CONFIG_BODY(double, Double
)
201 CONFIG_BODY(std::string
, String
)
203 static HackStrictOption
GetHackStrictOption(const IniSettingMap
& ini
,
205 auto val
= Config::GetString(ini
, config
);
207 if (Option::EnableHipHopSyntax
|| RuntimeOption::EnableHipHopSyntax
) {
208 return HackStrictOption::ERROR
;
210 return HackStrictOption::OFF
;
213 return HackStrictOption::WARN
;
216 ini_on_update(val
, ret
);
217 return ret
? HackStrictOption::ERROR
: HackStrictOption::OFF
;
220 void Config::Bind(HackStrictOption
& loc
, const IniSettingMap
& ini
,
222 // Currently this doens't bind to ini_get since it is hard to thread through
224 loc
= GetHackStrictOption(ini
, config
);
227 void Config::Bind(std::vector
<std::string
>& loc
, const IniSettingMap
& ini
,
229 std::vector
<std::string
> ret
;
230 auto ini_name
= IniName(config
);
231 auto* value
= ini
.get_ptr(ini_name
);
232 if (value
&& value
->isObject()) {
233 ini_on_update(*value
, ret
);
236 // If there is an HDF setting for the config, then it still wins for
237 // the RuntimeOption value until we obliterate HDFs
239 config
.configGet(ret
);
240 if (ret
.size() > 0) {
243 IniSetting::Bind(IniSetting::CORE
, IniSetting::PHP_INI_SYSTEM
, ini_name
,