PageRenderTime 65ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/src/runtime/base/ini_setting.cpp

https://github.com/kevlund/hiphop-php
C++ | 325 lines | 267 code | 35 blank | 23 comment | 112 complexity | 187822798f16804589922afc7e3ebc51 MD5 | raw file
  1. /*
  2. +----------------------------------------------------------------------+
  3. | HipHop for PHP |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) 2010- 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. +----------------------------------------------------------------------+
  15. */
  16. #include <runtime/base/ini_setting.h>
  17. #include <runtime/base/complex_types.h>
  18. #include <runtime/base/type_conversions.h>
  19. #include <runtime/base/builtin_functions.h>
  20. #include <runtime/base/hphp_system.h>
  21. #include <runtime/base/runtime_option.h>
  22. #include <runtime/base/timeout_thread.h>
  23. #include <runtime/ext/extension.h>
  24. #include <util/lock.h>
  25. using namespace std;
  26. ///////////////////////////////////////////////////////////////////////////////
  27. // defined in zend/zend_ini.tab.cpp
  28. extern bool zend_parse_ini_string
  29. (HPHP::CStrRef str, HPHP::CStrRef filename, int scanner_mode,
  30. HPHP::IniSetting::PFN_PARSER_CALLBACK callback, void *arg);
  31. namespace HPHP {
  32. ///////////////////////////////////////////////////////////////////////////////
  33. bool ini_on_update_bool(CStrRef value, void *p) {
  34. if (p) {
  35. if ((value.size() == 2 && strcasecmp("on", value.data()) == 0) ||
  36. (value.size() == 3 && strcasecmp("yes", value.data()) == 0) ||
  37. (value.size() == 4 && strcasecmp("true", value.data()) == 0)) {
  38. *((bool*)p) = true;
  39. } else {
  40. *((bool*)p) = value.toBoolean();
  41. }
  42. }
  43. return true;
  44. }
  45. bool ini_on_update_long(CStrRef value, void *p) {
  46. if (p) {
  47. *((int64*)p) = value.toInt64();
  48. }
  49. return true;
  50. }
  51. bool ini_on_update_non_negative(CStrRef value, void *p) {
  52. int64 v = value.toInt64();
  53. if (v < 0) {
  54. return false;
  55. }
  56. if (p) {
  57. *((int64*)p) = v;
  58. }
  59. return true;
  60. }
  61. bool ini_on_update_real(CStrRef value, void *p) {
  62. if (p) {
  63. *((double*)p) = value.toDouble();
  64. }
  65. return true;
  66. }
  67. bool ini_on_update_string(CStrRef value, void *p) {
  68. if (p) {
  69. *((std::string*)p) = std::string(value.data(), value.size());
  70. }
  71. return true;
  72. }
  73. bool ini_on_update_string_non_empty(CStrRef value, void *p) {
  74. if (value.empty()) {
  75. return false;
  76. }
  77. if (p) {
  78. *((std::string*)p) = std::string(value.data(), value.size());
  79. }
  80. return true;
  81. }
  82. ///////////////////////////////////////////////////////////////////////////////
  83. // callbacks for creating arrays out of ini
  84. static void php_simple_ini_parser_cb
  85. (String *arg1, String *arg2, String *arg3, int callback_type, void *arg) {
  86. ASSERT(arg1);
  87. if (!arg1 || !arg2) return;
  88. Variant *arr = (Variant*)arg;
  89. switch (callback_type) {
  90. case IniSetting::ParserEntry:
  91. arr->set(*arg1, *arg2);
  92. break;
  93. case IniSetting::ParserPopEntry:
  94. {
  95. Variant &hash = arr->lvalAt(*arg1);
  96. if (!hash.isArray()) {
  97. hash = Array::Create();
  98. }
  99. if (arg3 && !arg3->empty()) {
  100. hash.set(*arg3, *arg2);
  101. } else {
  102. hash.append(*arg2);
  103. }
  104. }
  105. break;
  106. }
  107. }
  108. struct CallbackData {
  109. Variant active_section;
  110. Variant arr;
  111. };
  112. static void php_ini_parser_cb_with_sections
  113. (String *arg1, String *arg2, String *arg3, int callback_type, void *arg) {
  114. ASSERT(arg1);
  115. if (!arg1) return;
  116. CallbackData *data = (CallbackData*)arg;
  117. Variant *arr = &data->arr;
  118. if (callback_type == IniSetting::ParserSection) {
  119. data->active_section.unset(); // break ref() from previous section
  120. data->active_section = Array::Create();
  121. arr->set(*arg1, ref(data->active_section));
  122. } else if (arg2) {
  123. Variant *active_arr;
  124. if (!data->active_section.isNull()) {
  125. active_arr = &data->active_section;
  126. } else {
  127. active_arr = arr;
  128. }
  129. php_simple_ini_parser_cb(arg1, arg2, arg3, callback_type, active_arr);
  130. }
  131. }
  132. ///////////////////////////////////////////////////////////////////////////////
  133. static Mutex s_mutex;
  134. Variant IniSetting::FromString(CStrRef ini, CStrRef filename,
  135. bool process_sections, int scanner_mode) {
  136. Lock lock(s_mutex); // ini parser is not thread-safe
  137. if (process_sections) {
  138. CallbackData data;
  139. data.arr = Array::Create();
  140. if (zend_parse_ini_string
  141. (ini, filename, scanner_mode, php_ini_parser_cb_with_sections, &data)){
  142. return data.arr;
  143. }
  144. } else {
  145. Variant ret = Array::Create();
  146. if (zend_parse_ini_string
  147. (ini, filename, scanner_mode, php_simple_ini_parser_cb, &ret)) {
  148. return ret;
  149. }
  150. }
  151. return false;
  152. }
  153. struct UpdateCallbackData {
  154. IniSetting::PFN_UPDATE_CALLBACK callback;
  155. void *p;
  156. };
  157. typedef std::map<std::string, UpdateCallbackData> CallbackMap;
  158. static IMPLEMENT_THREAD_LOCAL(CallbackMap, s_callbacks);
  159. typedef std::map<std::string, std::string> DefaultMap;
  160. static DefaultMap s_global_ini;
  161. void IniSetting::SetGlobalDefault(const char *name, const char *value) {
  162. ASSERT(name && *name);
  163. ASSERT(value);
  164. ASSERT(!Extension::ModulesInitialised());
  165. s_global_ini[name] = value;
  166. }
  167. void IniSetting::Bind(const char *name, const char *value,
  168. PFN_UPDATE_CALLBACK callback, void *p /* = NULL */) {
  169. ASSERT(name && *name);
  170. ASSERT(value);
  171. UpdateCallbackData &data = (*s_callbacks)[name];
  172. data.callback = callback;
  173. data.p = p;
  174. (*callback)(value, p);
  175. }
  176. void IniSetting::Unbind(const char *name) {
  177. ASSERT(name && *name);
  178. s_callbacks->erase(name);
  179. }
  180. bool IniSetting::Get(CStrRef name, String &value) {
  181. if (name == "error_reporting") {
  182. value = String((int64)g_context->getErrorReportingLevel());
  183. return true;
  184. }
  185. if (name == "memory_limit") {
  186. value = String((int64)g_context->getRequestMemoryMaxBytes());
  187. return true;
  188. }
  189. if (name == "max_execution_time" || name == "maximum_execution_time") {
  190. value = String((int64)g_context->getRequestTimeLimit());
  191. return true;
  192. }
  193. if (name == "hphp.build_id") {
  194. value = String(RuntimeOption::BuildId);
  195. return true;
  196. }
  197. if (name == "hphp.compiler_version") {
  198. value = String(getHphpCompilerVersion());
  199. return true;
  200. }
  201. if (name == "hphp.compiler_id") {
  202. value = String(getHphpCompilerId());
  203. return true;
  204. }
  205. if (name == "arg_separator.output") {
  206. value = g_context->getArgSeparatorOutput();
  207. return true;
  208. }
  209. if (name == "upload_max_filesize") {
  210. int uploadMaxFilesize = VirtualHost::GetUploadMaxFileSize() / (1 << 20);
  211. value = String(uploadMaxFilesize);
  212. return true;
  213. }
  214. if (name == "log_errors") {
  215. value = g_context->getLogErrors() ? "1" : "0";
  216. return true;
  217. }
  218. if (name == "error_log") {
  219. value = g_context->getErrorLog();
  220. return true;
  221. }
  222. if (name == "notice_frequency") {
  223. value = String((int64)RuntimeOption::NoticeFrequency);
  224. return true;
  225. }
  226. if (name == "warning_frequency") {
  227. value = String((int64)RuntimeOption::WarningFrequency);
  228. return true;
  229. }
  230. if (name == "include_path") {
  231. value = g_context->getIncludePath();
  232. return true;
  233. }
  234. DefaultMap::iterator iter = s_global_ini.find(name.data());
  235. if (iter != s_global_ini.end()) {
  236. value = iter->second;
  237. return true;
  238. }
  239. return false;
  240. }
  241. bool IniSetting::Set(CStrRef name, CStrRef value) {
  242. CallbackMap::iterator iter = s_callbacks->find(name.data());
  243. if (iter != s_callbacks->end()) {
  244. return (*iter->second.callback)(value, iter->second.p);
  245. }
  246. if (name == "memory_limit") {
  247. if (!value.empty()) {
  248. int64 newInt = value.toInt64();
  249. char lastChar = value.charAt(value.size() - 1);
  250. if (lastChar == 'K' || lastChar == 'k') {
  251. newInt <<= 10;
  252. } else if (lastChar == 'M' || lastChar == 'm') {
  253. newInt <<= 20;
  254. } else if (lastChar == 'G' || lastChar == 'g') {
  255. newInt <<= 30;
  256. }
  257. g_context->setRequestMemoryMaxBytes(newInt);
  258. return true;
  259. }
  260. } else if (name == "max_execution_time" || name == "maximum_execution_time"){
  261. int64 limit = value.toInt64();
  262. TimeoutThread::DeferTimeout(limit);
  263. // Just for ini_get
  264. g_context->setRequestTimeLimit(limit);
  265. return true;
  266. } else if (name == "arg_separator.output") {
  267. g_context->setArgSeparatorOutput(value);
  268. return true;
  269. } else if (name == "log_errors") {
  270. bool log;
  271. ini_on_update_bool(value, &log);
  272. g_context->setLogErrors(log);
  273. return true;
  274. } else if (name == "error_log") {
  275. g_context->setErrorLog(value);
  276. return true;
  277. } else if (name == "notice_frequency") {
  278. RuntimeOption::NoticeFrequency = value.toInt64();
  279. return true;
  280. } else if (name == "warning_frequency") {
  281. RuntimeOption::WarningFrequency = value.toInt64();
  282. return true;
  283. } else if (name == "include_path") {
  284. g_context->setIncludePath(value);
  285. return true;
  286. }
  287. return false;
  288. }
  289. ///////////////////////////////////////////////////////////////////////////////
  290. }