Add sub-controls for Hack array compat runtime checks
[hiphop-php.git] / hphp / runtime / base / ini-setting.h
blob9f41b63e626112734f7acb4fae10c7aab451ca8c
1 /*
2 +----------------------------------------------------------------------+
3 | HipHop for PHP |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-present 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 #ifndef incl_HPHP_INI_SETTING_H_
18 #define incl_HPHP_INI_SETTING_H_
20 #include "hphp/runtime/base/type-variant.h"
22 #include <folly/Range.h>
24 #include <cstdint>
25 #include <functional>
26 #include <set>
27 #include <string>
29 namespace HPHP {
30 ///////////////////////////////////////////////////////////////////////////////
32 struct Array;
33 struct Extension;
34 struct String;
36 bool ini_on_update(const Variant& value, bool& p);
37 bool ini_on_update(const Variant& value, double& p);
38 bool ini_on_update(const Variant& value, char& p);
39 bool ini_on_update(const Variant& value, int16_t& p);
40 bool ini_on_update(const Variant& value, int32_t& p);
41 bool ini_on_update(const Variant& value, int64_t& p);
42 bool ini_on_update(const Variant& value, unsigned char& p);
43 bool ini_on_update(const Variant& value, uint16_t& p);
44 bool ini_on_update(const Variant& value, uint32_t& p);
45 bool ini_on_update(const Variant& value, uint64_t& p);
46 bool ini_on_update(const Variant& value, std::string& p);
47 bool ini_on_update(const Variant& value, String& p);
48 bool ini_on_update(const Variant& value, Array& p);
49 bool ini_on_update(const Variant& value, std::set<std::string>& p);
50 bool ini_on_update(const Variant& value, std::vector<std::string>& p);
51 bool ini_on_update(const Variant& value,
52 std::map<std::string, std::string>& p);
53 bool ini_on_update(const Variant& value,
54 std::map<std::string, std::string, stdltistr>& p);
55 bool ini_on_update(const Variant& value,
56 std::set<std::string, stdltistr>& p);
57 bool ini_on_update(const Variant& value,
58 boost::container::flat_set<std::string>& p);
59 bool ini_on_update(const Variant& value,
60 hphp_string_imap<std::string>& p);
61 Variant ini_get(bool& p);
62 Variant ini_get(double& p);
63 Variant ini_get(char& p);
64 Variant ini_get(int16_t& p);
65 Variant ini_get(int32_t& p);
66 Variant ini_get(int64_t& p);
67 Variant ini_get(unsigned char& p);
68 Variant ini_get(uint16_t& p);
69 Variant ini_get(uint32_t& p);
70 Variant ini_get(uint64_t& p);
71 Variant ini_get(std::string& p);
72 Variant ini_get(String& p);
73 Variant ini_get(Array& p);
74 Variant ini_get(std::set<std::string>& p);
75 Variant ini_get(std::vector<std::string>& p);
76 Variant ini_get(std::map<std::string, std::string>& p);
77 Variant ini_get(std::map<std::string, std::string, stdltistr>& p);
78 Variant ini_get(std::set<std::string, stdltistr>& p);
79 Variant ini_get(boost::container::flat_set<std::string>& p);
80 Variant ini_get(hphp_string_imap<std::string>& p);
82 /**
83 * If given an ini setting like "hhvm.abc[def][ghi]=yyy" and we have
84 * an ini Variant with the top key being hhvm.abc pointing to its
85 * values, we will have something like:
86 * {hhvm.abc {def {ghi : yyy}}}
87 * And we pass as the name to get the value of as "def.ghi" for that
88 * Variant, we need to iterate over the pointer for the dot (.) values to
89 * get to the final setting value of yyy
91 const IniSettingMap ini_iterate(const IniSettingMap& ini,
92 const std::string& name);
95 * Consult the private implementation details in ini-setting.cpp.
97 * There's one instance of an IniCallbackData for each initialization
98 * setting. Management of system and per-request (per-thread)
99 * mappings from names of ini settings to actual IniCallbackData
100 * is done privately with the statics s_user_callbacks and
101 * s_system_ini_callbacks.
103 * In addition, a unique instance of the struct UserIniData can be
104 * associated with the IniCallbackData. The IniCallbackData instance
105 * is the point of ownership of the instance of UserIniData, and is
106 * responsible for firing the destructor.
108 * The struct UserIniData should be subclassed to hold data specific
109 * to an initialization regime, such as the zend compatibility layer
110 * implementation of zend_ini_entry. That subclass is responsible for
111 * allocating/freeing its own internal data.
113 * There's a mechanism for registering an initter, which is a factory to
114 * produce UserIniData. This registration is done at the same time that
115 * the setter and getter are established; see the class SetAndGet
117 struct UserIniData {
118 virtual ~UserIniData() {}
121 struct IniSettingMap {
122 // placeholder to allow the form:
123 // IniSettingMap ini = IniSettingMap::object;
124 // is used throughout the codebase. We can convert later to remove them
125 enum Type { object };
126 IniSettingMap();
127 /* implicit */ IniSettingMap(Type);
128 /* implicit */ IniSettingMap(const IniSettingMap& i); // copy constructor
129 /* implicit */ IniSettingMap(const Variant& v);
130 /* implicit */ IniSettingMap(IniSettingMap&& i) noexcept; // move constructor
131 IniSettingMap& operator=(const IniSettingMap& i);
133 public:
134 const IniSettingMap operator[](const String& key) const;
135 String toString() const { return m_map.toString();}
136 Array toArray() const { return m_map.toArray();}
137 Array& toArrRef() { return m_map.toArrRef(); }
138 Object toObject() const { return m_map.toObject();}
139 bool isNull() const { return m_map.isNull();}
140 bool isString() const { return m_map.isString();}
141 bool isArray() const { return m_map.isArray();}
142 bool isObject() const { return m_map.isObject();}
143 Variant& toVariant() { return m_map; }
144 void set(const String& key, const Variant& v);
145 TypedValue detach() noexcept {
146 return m_map.detach();
148 private:
149 Variant m_map;
152 struct IniSetting {
153 private:
155 struct CallbackData {
156 Variant active_section;
157 Variant arr;
160 public:
161 // can remove later in a diff that explicitly changes all uses of
162 // IniSetting::Map to IniSettingMap
163 typedef IniSettingMap Map;
164 static const Extension* CORE;
165 enum ScannerMode {
166 NormalScanner,
167 RawScanner,
170 struct ParserCallback {
171 virtual ~ParserCallback() {};
172 virtual void onSection(const std::string &name, void *arg);
173 virtual void onLabel(const std::string &name, void *arg);
174 virtual void onEntry(const std::string &key, const std::string &value,
175 void *arg);
176 virtual void onPopEntry(const std::string &key, const std::string &value,
177 const std::string &offset, void *arg);
178 virtual void onConstant(std::string &result, const std::string &name);
179 virtual void onVar(std::string &result, const std::string &name);
180 virtual void onOp(std::string &result, char type, const std::string& op1,
181 const std::string& op2);
182 protected:
183 void makeArray(Variant &hash, const std::string &offset,
184 const std::string &value);
185 private:
186 // Substitution copy or symlink via @ or : markers in the config line
187 void makeSettingSub(const String &key, const std::string &offset,
188 const std::string &value, Variant& cur_settings);
189 void traverseToSet(const String &key, const std::string& offset,
190 Variant& value, Variant& cur_settings,
191 const std::string& stopChar);
193 struct SectionParserCallback : ParserCallback {
194 void onSection(const std::string& name, void* arg) override;
195 void onLabel(const std::string& name, void* arg) override;
196 void onEntry(const std::string& key, const std::string& value, void* arg)
197 override;
198 void onPopEntry(
199 const std::string& key,
200 const std::string& value,
201 const std::string& offset,
202 void* arg) override;
204 private:
205 Variant* activeArray(CallbackData* data);
207 struct SystemParserCallback : ParserCallback {
208 void onEntry(const std::string& key, const std::string& value, void* arg)
209 override;
210 void onPopEntry(
211 const std::string& key,
212 const std::string& value,
213 const std::string& offset,
214 void* arg) override;
215 void onConstant(std::string& result, const std::string& name) override;
218 enum Mode {
219 PHP_INI_NONE = 0,
220 // These 3 match zend
221 PHP_INI_USER = (1u << 0),
222 PHP_INI_PERDIR = (1u << 1),
223 PHP_INI_SYSTEM = (1u << 2),
225 PHP_INI_ONLY = (1u << 3),
226 PHP_INI_ALL = (1u << 4),
228 PHP_INI_SET_USER = PHP_INI_USER | PHP_INI_ALL,
229 PHP_INI_SET_EVERY = PHP_INI_ONLY | PHP_INI_SYSTEM | PHP_INI_PERDIR |
230 PHP_INI_SET_USER,
233 public:
234 static Variant FromString(const String& ini, const String& filename,
235 bool process_sections = false,
236 int scanner_mode = NormalScanner);
237 static IniSettingMap FromStringAsMap(const std::string& ini,
238 const std::string& filename);
240 static bool Get(const std::string& name, std::string &value);
241 static bool Get(const String& name, Variant& value);
242 static bool Get(const String& name, String& value);
243 static std::string Get(const std::string& name);
244 static Array GetAll(const String& extension, bool details);
245 static std::string GetAllAsJSON();
248 * Change an INI setting as if it was in the php.ini file
250 static bool SetSystem(const String& name, const Variant& value);
252 * Get a system value
254 static bool GetSystem(const String& name, Variant& value);
257 * Change an INI setting as if there was a call to ini_set()
259 static bool SetUser(const String& name, const Variant& value);
262 * Restore an INI setting to the default value before the first call to
263 * SetUser().
265 static void RestoreUser(const String& name);
268 * Fill in constant that may not have been bound when an
269 * ini file was initially parsed
271 static bool FillInConstant(const std::string& name,
272 const Variant& value);
274 * Get the mode for a setting
276 static bool GetMode(const std::string& name, Mode& mode);
278 template<class T>
279 struct SetAndGet {
280 explicit SetAndGet(
281 std::function<bool (const T&)> setter,
282 std::function<T ()> getter,
283 std::function<struct UserIniData *()>initter = nullptr)
284 : setter(setter),
285 getter(getter),
286 initter(initter) {}
288 explicit SetAndGet() {}
290 std::function<bool (const T&)> setter;
291 std::function<T ()> getter;
292 std::function<struct UserIniData *()> initter;
296 * The heavy lifting of creating ini settings. First of all, if you don't
297 * have to use this method, please don't. Instead use the simpler:
299 * IniSetting::Bind(this, PHP_INI_SYSTEM, "my.ini", &some_global_var);
300 * or
301 * IniSetting::Bind(this, PHP_INI_ALL, "my.ini", &some_thread_local_var);
303 * If you have to do something special before your variable is set or gotten
304 * then you can use this function to add callbacks. Both callbacks are
305 * optional (but if you don't pass any, why are you using this method in the
306 * first place?). If the setter callback returns "false" then the value will
307 * not be saved into p. If the getter is not provided, the contents of p will
308 * directly be used.
310 template<class T>
311 static void Bind(const Extension* extension, const Mode mode,
312 const std::string& name, const char *defaultValue,
313 SetAndGet<T> callbacks, T* p = nullptr) {
314 auto callback_set = callbacks.setter;
315 auto setter = [callback_set, p](const Variant &value) {
316 T v;
317 auto ret = ini_on_update(value, v);
318 if (!ret) {
319 return false;
321 if (callback_set) {
322 ret = callback_set(v);
323 if (!ret) {
324 return false;
327 if (p) {
328 *p = v;
330 return true;
332 auto callback_get = callbacks.getter;
333 auto getter = [callback_get, p]() {
334 T v;
335 if (callback_get) {
336 v = callback_get();
337 } else if (p) {
338 v = *p;
340 return ini_get(v);
342 Bind(extension, mode, name, setter, getter, callbacks.initter);
343 auto hasSystemDefault = ResetSystemDefault(name);
344 if (!hasSystemDefault && defaultValue) {
345 setter(defaultValue);
349 template<class T>
350 static void Bind(const Extension* extension, const Mode mode,
351 const std::string& name, SetAndGet<T> callbacks,
352 T* p = nullptr) {
353 Bind(extension, mode, name, nullptr, callbacks, p);
357 * Prefer to use this method whenever possible (the non-default one is ok
358 * too). Use Config::Bind if immediate access to the ini setting is
359 * necessary. For performance reasons, Config::Bind should only be used
360 * when access to the ini setting is needed prior to loading the rest of
361 * the ini settings.
363 template<class T>
364 static void Bind(const Extension* extension, const Mode mode,
365 const std::string& name, const char *defaultValue, T *p) {
366 Bind(extension, mode, name, defaultValue, SetAndGet<T>(), p);
369 template<class T>
370 static void Bind(const Extension* extension, const Mode mode,
371 const std::string& name, T *p) {
372 Bind(extension, mode, name, nullptr, p);
375 static void Unbind(const std::string& name);
378 * Set an ini setting back to the value from the config file
379 * (or the hard-coded default)
381 static bool ResetSystemDefault(const std::string& name);
384 * After a request, we want to set all user settings back to their original
385 * defaults before the request. This should be called on requestShutdown.
387 static void ResetSavedDefaults();
390 * Used to help us late bind extension constants (e.g. E_ALL) that
391 * were incorrectly bound initially, and needed to be bound again after
392 * all was loaded.
394 static bool s_config_is_a_constant;
395 static std::set<std::string> config_names_that_use_constants;
398 * A flag to ensure we don't try to add a system setting after the
399 * runtime options have been loaded
401 static bool s_system_settings_are_set;
403 private:
404 static void Bind(
405 const Extension* extension,
406 const Mode mode,
407 const std::string& name,
408 std::function<bool(const Variant&)>updateCallback,
409 std::function<Variant()> getCallback,
410 std::function<UserIniData *(void)> userDataCallback = nullptr);
413 * Take a Variant full of KindOfRefs and unbox it.
415 static Variant Unbox(const Variant& boxed, std::set<ArrayData*>& seen,
416 bool& use_defaults, const String& array_key);
419 int64_t convert_bytes_to_long(folly::StringPiece value);
420 std::string convert_long_to_bytes(int64_t value);
422 void add_default_config_files_globbed(
423 const char *default_config_file,
424 std::function<void (const char *filename)> cb);
426 ///////////////////////////////////////////////////////////////////////////////
429 #endif // incl_HPHP_INI_SETTING_H_