]>
Commit | Line | Data |
---|---|---|
1 | <?php\r | |
2 | /* Full-Text RSS config */\r | |
3 | \r | |
4 | // ......IMPORTANT......................................\r | |
5 | // .....................................................\r | |
6 | // Please do not change this file (config.php) directly.\r | |
7 | // Save a copy as custom_config.php and make your\r | |
8 | // changes to that instead. It will automatically\r | |
9 | // override anything in config.php. Because config.php\r | |
10 | // always gets loaded anyway, you can simply specify\r | |
11 | // options you'd like to override in custom_config.php.\r | |
12 | // .....................................................\r | |
13 | \r | |
14 | global $options;\r | |
15 | \r | |
16 | // Create config object\r | |
17 | if (!isset($options)) $options = new stdClass();\r | |
18 | \r | |
19 | // Enable service\r | |
20 | // ----------------------\r | |
21 | // Set this to false if you want to disable the service.\r | |
22 | // If set to false, no feed is produced and users will\r | |
23 | // be told that the service is disabled.\r | |
24 | $options->enabled = true;\r | |
25 | \r | |
26 | // Debug mode\r | |
27 | // ----------------------\r | |
28 | // Enable or disable debugging. When enabled debugging works by passing\r | |
29 | // &debug to the makefulltextfeed.php querystring.\r | |
30 | // Valid values:\r | |
31 | // true or 'user' (default) - let user decide\r | |
32 | // 'admin' - debug works only for logged in admin users\r | |
33 | // false - disabled\r | |
34 | $options->debug = true;\r | |
35 | \r | |
36 | // Default entries (without access key)\r | |
37 | // ----------------------\r | |
38 | // The number of feed items to process when no API key is supplied\r | |
39 | // and no &max=x value is supplied in the querystring.\r | |
40 | $options->default_entries = 5;\r | |
41 | \r | |
42 | // Max entries (without access key)\r | |
43 | // ----------------------\r | |
44 | // The maximum number of feed items to process when no access key is supplied.\r | |
45 | // This limits the user-supplied &max=x value. For example, if the user\r | |
46 | // asks for 20 items to be processed (&max=20), if max_entries is set to\r | |
47 | // 10, only 10 will be processed.\r | |
48 | $options->max_entries = 10;\r | |
49 | \r | |
50 | // Full content\r | |
51 | // ----------------------\r | |
52 | // By default Full-Text RSS includes the extracted content in the output.\r | |
53 | // You can exclude this from the output by passing '&content=0' in the querystring.\r | |
54 | //\r | |
55 | // Possible values...\r | |
56 | // Always include: true\r | |
57 | // Never include: false\r | |
58 | // Include unless user overrides (&content=0): 'user' (default)\r | |
59 | //\r | |
60 | // Note: currently this does not disable full content extraction. It simply omits it\r | |
61 | // from the output.\r | |
62 | $options->content = 'user';\r | |
63 | \r | |
64 | // Excerpts\r | |
65 | // ----------------------\r | |
66 | // By default Full-Text RSS does not include excerpts in the output.\r | |
67 | // You can enable this by passing '&summary=1' in the querystring.\r | |
68 | // This will include a plain text excerpt from the extracted content.\r | |
69 | //\r | |
70 | // Possible values...\r | |
71 | // Always include: true (recommended for new users)\r | |
72 | // Never include: false\r | |
73 | // Don't include unless user overrides (&summary=1): 'user' (default)\r | |
74 | //\r | |
75 | // Important: if both content and excerpts are requested, the excerpt will be\r | |
76 | // placed in the description element and the full content inside content:encoded.\r | |
77 | // If excerpts are not requested, the full content will go inside the description element.\r | |
78 | //\r | |
79 | // Why are we not returning both excerpts and content by default?\r | |
80 | // Mainly for backward compatibility.\r | |
81 | // Excerpts should appear in the feed item's description element. Previous versions\r | |
82 | // of Full-Text RSS did not return excerpts, so the description element was always\r | |
83 | // used for the full content (as recommended by the RSS advisory). When returning both,\r | |
84 | // we need somewhere else to place the content (content:encoded).\r | |
85 | // Having both enabled should not create any problems for news readers, but it may create\r | |
86 | // problems for developers upgrading from one of our earlier versions who may now find\r | |
87 | // their applications are returning excerpts instead of the full content they were\r | |
88 | // expecting. To avoid such surprises for users who are upgrading Full-Text RSS,\r | |
89 | // excerpts must be explicitly requested in the querystring by default.\r | |
90 | //\r | |
91 | // Why not use a different element name for excerpts?\r | |
92 | // According to the RSS advisory:\r | |
93 | // "Publishers who employ summaries should store the summary in description and\r | |
94 | // the full content in content:encoded, ordering description first within the item.\r | |
95 | // On items with no summary, the full content should be stored in description."\r | |
96 | // See: http://www.rssboard.org/rss-profile#namespace-elements-content-encoded\r | |
97 | //\r | |
98 | // For more consistent element naming, we recommend new users set this option to true.\r | |
99 | // The full content can still be excluded via the querystring, but the element names\r | |
100 | // will not change: when $options->summary = true, the description element will always\r | |
101 | // be reserved for the excerpt and content:encoded always for full content.\r | |
102 | $options->summary = 'user';\r | |
103 | \r | |
104 | // Rewrite relative URLs\r | |
105 | // ----------------------\r | |
106 | // With this enabled relative URLs found in the extracted content\r | |
107 | // block are automatically rewritten as absolute URLs.\r | |
108 | $options->rewrite_relative_urls = true;\r | |
109 | \r | |
110 | // Exclude items if extraction fails\r | |
111 | // ---------------------------------\r | |
112 | // Excludes items from the resulting feed\r | |
113 | // if we cannot extract any content from the\r | |
114 | // item URL.\r | |
115 | // Possible values...\r | |
116 | // Enable: true\r | |
117 | // Disable: false (default)\r | |
118 | // User decides: 'user' (this option will appear on the form)\r | |
119 | $options->exclude_items_on_fail = 'user';\r | |
120 | \r | |
121 | // Enable multi-page support\r | |
122 | // -------------------------\r | |
123 | // If enabled, we will try to follow next page links on multi-page articles.\r | |
124 | // Currently this only happens for sites where next_page_link has been defined\r | |
125 | // in a site config file.\r | |
126 | $options->multipage = true;\r | |
127 | \r | |
128 | // Enable caching\r | |
129 | // ----------------------\r | |
130 | // Enable this if you'd like to cache results\r | |
131 | // for 10 minutes. Cache files are written to disk (in cache/ subfolders\r | |
132 | // - which must be writable).\r | |
133 | // Initially it's best to keep this disabled to make sure everything works\r | |
134 | // as expected. If you have APC enabled, please also see smart_cache in the\r | |
135 | // advanced section.\r | |
136 | $options->caching = false;\r | |
137 | \r | |
138 | // Cache directory\r | |
139 | // ----------------------\r | |
140 | // Only used if caching is true\r | |
141 | $options->cache_dir = dirname(__FILE__).'/cache';\r | |
142 | \r | |
143 | // Message to prepend (without access key)\r | |
144 | // ----------------------\r | |
145 | // HTML to insert at the beginning of each feed item when no access key is supplied.\r | |
146 | // Substitution tags:\r | |
147 | // {url} - Feed item URL\r | |
148 | // {effective-url} - Feed item URL after we've followed all redirects\r | |
149 | $options->message_to_prepend = '';\r | |
150 | \r | |
151 | // Message to append (without access key)\r | |
152 | // ----------------------\r | |
153 | // HTML to insert at the end of each feed item when no access key is supplied.\r | |
154 | // Substitution tags:\r | |
155 | // {url} - Feed item URL\r | |
156 | // {effective-url} - Feed item URL after we've followed all redirects\r | |
157 | $options->message_to_append = '';\r | |
158 | \r | |
159 | // Error message when content extraction fails (without access key)\r | |
160 | // ----------------------\r | |
161 | $options->error_message = '[unable to retrieve full-text content]';\r | |
162 | \r | |
163 | // Keep enclosure in feed items\r | |
164 | // If enabled, we will try to preserve enclosures if present.\r | |
165 | // ----------------------\r | |
166 | $options->keep_enclosures = true;\r | |
167 | \r | |
168 | // Detect language\r | |
169 | // ---------------\r | |
170 | // Should we try and find/guess the language of the article being processed?\r | |
171 | // Values will be placed inside the <dc:language> element inside each <item> element\r | |
172 | // Possible values:\r | |
173 | // * Ignore language: 0\r | |
174 | // * Use article/feed metadata (e.g. HTML lang attribute): 1 (default)\r | |
175 | // * As above, but guess if not present: 2\r | |
176 | // * Always guess: 3\r | |
177 | // * User decides: 'user' (value of 0-3 can be passed in querystring: e.g. &l=2)\r | |
178 | $options->detect_language = 1;\r | |
179 | \r | |
180 | // Registration key\r | |
181 | // ---------------\r | |
182 | // The registration key is optional. It is not required to use Full-Text RSS,\r | |
183 | // and does not affect the normal operation of Full-Text RSS. It is currently\r | |
184 | // only used on admin pages which help you update site patterns with the\r | |
185 | // latest version offered by FiveFilters.org. For these admin-related\r | |
186 | // tasks to complete, we will require a valid registration key.\r | |
187 | // If you would like one, you can purchase the latest version of Full-Text RSS\r | |
188 | // at http://fivefilters.org/content-only/\r | |
189 | // Your registration key will automatically be sent in the confirmation email.\r | |
190 | // Once you have it, simply copy and paste it here.\r | |
191 | $options->registration_key = '';\r | |
192 | \r | |
193 | /////////////////////////////////////////////////\r | |
194 | /// RESTRICT ACCESS /////////////////////////////\r | |
195 | /////////////////////////////////////////////////\r | |
196 | \r | |
197 | // Admin credentials\r | |
198 | // ----------------------\r | |
199 | // Certain pages/actions, e.g. updating site patterns with our online tool, will require admin credentials.\r | |
200 | // To use these pages, enter a password here and you'll be prompted for it when you try to access those pages.\r | |
201 | // If no password or username is set, pages requiring admin privelages will be inaccessible.\r | |
202 | // The default username is 'admin'.\r | |
203 | // If overriding with an environment variable, separate username and password with a colon, e.g.:\r | |
204 | // ftr_admin_credentials: admin:my-secret-password\r | |
205 | // Example: $options->admin_credentials = array('username'=>'admin', 'password'=>'my-secret-password');\r | |
206 | $options->admin_credentials = array('username'=>'admin', 'password'=>'');\r | |
207 | \r | |
208 | // URLs to allow\r | |
209 | // ----------------------\r | |
210 | // List of URLs (or parts of a URL) which the service will accept.\r | |
211 | // If the list is empty, all URLs (except those specified in the blocked list below)\r | |
212 | // will be permitted.\r | |
213 | // Empty: array();\r | |
214 | // Non-empty example: array('example.com', 'anothersite.org');\r | |
215 | $options->allowed_urls = array();\r | |
216 | \r | |
217 | // URLs to block\r | |
218 | // ----------------------\r | |
219 | // List of URLs (or parts of a URL) which the service will not accept.\r | |
220 | // Note: this list is ignored if allowed_urls is not empty\r | |
221 | $options->blocked_urls = array();\r | |
222 | \r | |
223 | // Key holder(s) only?\r | |
224 | // ----------------------\r | |
225 | // Set this to true if you want to restrict access only to\r | |
226 | // those with a key (see below to specify key(s)).\r | |
227 | // If set to true, no feed is produced unless a valid\r | |
228 | // key is provided.\r | |
229 | $options->key_required = false;\r | |
230 | \r | |
231 | // Favour item titles in feed\r | |
232 | // ----------------------\r | |
233 | // By default, when processing feeds, we assume item titles in the feed\r | |
234 | // have not been truncated. So after processing web pages, the extracted titles\r | |
235 | // are not used in the generated feed. If you prefer to have extracted titles in\r | |
236 | // the feed you can either set this to false, in which case we will always favour\r | |
237 | // extracted titles. Alternatively, if set to 'user' (default) we'll use the\r | |
238 | // extracted title if you pass '&use_extracted_title' in the querystring.\r | |
239 | // Possible values:\r | |
240 | // * Favour feed titles: true\r | |
241 | // * Favour extracted titles: false\r | |
242 | // * Favour feed titles with user override: 'user' (default)\r | |
243 | // Note: this has no effect when the input URL is to a web page - in these cases\r | |
244 | // we always use the extracted title in the generated feed.\r | |
245 | $options->favour_feed_titles = 'user';\r | |
246 | \r | |
247 | // Access keys (password protected access)\r | |
248 | // ------------------------------------\r | |
249 | // NOTE: You do not need an API key from fivefilters.org to run your own\r | |
250 | // copy of the code. This is here if you'd like to restrict access to\r | |
251 | // _your_ copy.\r | |
252 | // Keys let you group users - those with a key and those without - and\r | |
253 | // restrict access to the service to those without a key.\r | |
254 | // If you want everyone to access the service in the same way, you can\r | |
255 | // leave the array below empty and ignore the access key options further down.\r | |
256 | // The options further down let you control how the service should behave\r | |
257 | // in each mode.\r | |
258 | // Note: Explicitly including the index number (1 and 2 in the examples below)\r | |
259 | // is highly recommended (when generating feeds, we encode the key and\r | |
260 | // refer to it by index number and hash).\r | |
261 | $options->api_keys = array();\r | |
262 | // Example:\r | |
263 | // $options->api_keys[1] = 'secret-key-1';\r | |
264 | // $options->api_keys[2] = 'secret-key-2';\r | |
265 | \r | |
266 | // Default entries (with access key)\r | |
267 | // ----------------------\r | |
268 | // The number of feed items to process when a valid access key is supplied.\r | |
269 | $options->default_entries_with_key = 5;\r | |
270 | \r | |
271 | // Max entries (with access key)\r | |
272 | // ----------------------\r | |
273 | // The maximum number of feed items to process when a valid access key is supplied.\r | |
274 | $options->max_entries_with_key = 10;\r | |
275 | \r | |
276 | /////////////////////////////////////////////////\r | |
277 | /// ADVANCED OPTIONS ////////////////////////////\r | |
278 | /////////////////////////////////////////////////\r | |
279 | \r | |
280 | // Enable XSS filter?\r | |
281 | // ----------------------\r | |
282 | // We have not enabled this by default because we assume the majority of\r | |
283 | // our users do not display the HTML retrieved by Full-Text RSS\r | |
284 | // in a web page without further processing. If you subscribe to our generated\r | |
285 | // feeds in your news reader application, it should, if it's good software, already\r | |
286 | // filter the resulting HTML for XSS attacks, making it redundant for\r | |
287 | // Full-Text RSS do the same. Similarly with frameworks/CMS which display\r | |
288 | // feed content - the content should be treated like any other user-submitted content.\r | |
289 | //\r | |
290 | // If you are writing an application yourself which is processing feeds generated by\r | |
291 | // Full-Text RSS, you can either filter the HTML yourself to remove potential XSS attacks\r | |
292 | // or enable this option. This might be useful if you are processing our generated\r | |
293 | // feeds with JavaScript on the client side - although there's client side xss\r | |
294 | // filtering available too, e.g. https://code.google.com/p/google-caja/wiki/JsHtmlSanitizer\r | |
295 | //\r | |
296 | // If enabled, we'll pass retrieved HTML content through htmLawed with\r | |
297 | // safe flag on and style attributes denied, see\r | |
298 | // http://www.bioinformatics.org/phplabware/internal_utilities/htmLawed/htmLawed_README.htm#s3.6\r | |
299 | // Note: if enabled this will also remove certain elements you may want to preserve, such as iframes.\r | |
300 | //\r | |
301 | // Valid values:\r | |
302 | // true - enabled, all content will be filtered\r | |
303 | // 'user' (default) - user must pass &xss in makefulltextfeed.php querystring to enable\r | |
304 | // false - disabled\r | |
305 | $options->xss_filter = 'user';\r | |
306 | \r | |
307 | // Allowed parsers\r | |
308 | // ----------------------\r | |
309 | // Full-Text RSS attempts to use PHP's libxml extension to process HTML.\r | |
310 | // While fast, on some sites it may not always produce good results.\r | |
311 | // For these sites, you can specify an alternative HTML parser:\r | |
312 | // parser: html5lib\r | |
313 | // The html5lib parser is bundled with Full-Text RSS.\r | |
314 | // see http://code.google.com/p/html5lib/\r | |
315 | //\r | |
316 | // To disable HTML parsing with html5lib, you can remove it from this list.\r | |
317 | // By default we allow both: libxml and html5lib.\r | |
318 | $options->allowed_parsers = array('libxml', 'html5lib');\r | |
319 | //$options->allowed_parsers = array('libxml'); //disable html5lib - forcing libxml in all cases\r | |
320 | \r | |
321 | // Enable Cross-Origin Resource Sharing (CORS)\r | |
322 | // ----------------------\r | |
323 | // If enabled we'll send the following HTTP header\r | |
324 | // Access-Control-Allow-Origin: *\r | |
325 | // see http://en.wikipedia.org/wiki/Cross-origin_resource_sharing\r | |
326 | $options->cors = false;\r | |
327 | \r | |
328 | // Use APC user cache?\r | |
329 | // ----------------------\r | |
330 | // If enabled we will store site config files (when requested\r | |
331 | // for the first time) in APC's user cache. Keys prefixed with 'sc.'\r | |
332 | // This improves performance by reducing disk access.\r | |
333 | // Note: this has no effect if APC is unavailable on your server.\r | |
334 | $options->apc = true;\r | |
335 | \r | |
336 | // Smart cache (experimental)\r | |
337 | // ----------------------\r | |
338 | // With this option enabled we will not cache to disk immediately.\r | |
339 | // We will store the cache key in APC and if it's requested again\r | |
340 | // we will cache results to disk. Keys prefixed with 'cache.'\r | |
341 | // This improves performance by reducing disk access.\r | |
342 | // Note: this has no effect if APC is disabled or unavailable on your server,\r | |
343 | // or if you have caching disabled.\r | |
344 | $options->smart_cache = true;\r | |
345 | \r | |
346 | // Fingerprints\r | |
347 | // ----------------------\r | |
348 | // key is fingerprint (fragment to find in HTML)\r | |
349 | // value is host name to use for site config lookup if fingerprint matches\r | |
350 | $options->fingerprints = array(\r | |
351 | // Posterous\r | |
352 | '<meta name="generator" content="Posterous"' => array('hostname'=>'fingerprint.posterous.com', 'head'=>true),\r | |
353 | // Blogger\r | |
354 | '<meta content=\'blogger\' name=\'generator\'' => array('hostname'=>'fingerprint.blogspot.com', 'head'=>true),\r | |
355 | '<meta name="generator" content="Blogger"' => array('hostname'=>'fingerprint.blogspot.com', 'head'=>true),\r | |
356 | // WordPress (hosted)\r | |
357 | // '<meta name="generator" content="WordPress.com"' => array('hostname'=>'fingerprint.wordpress.com', 'head'=>true),\r | |
358 | // WordPress (self-hosted and hosted)\r | |
359 | '<meta name="generator" content="WordPress' => array('hostname'=>'fingerprint.wordpress.com', 'head'=>true)\r | |
360 | );\r | |
361 | \r | |
362 | // User Agent strings - mapping domain names\r | |
363 | // ----------------------\r | |
364 | // e.g. $options->user_agents = array('example.org' => 'PHP/5.2');\r | |
365 | $options->user_agents = array( 'lifehacker.com' => 'PHP/5.2',\r | |
366 | 'gawker.com' => 'PHP/5.2',\r | |
367 | 'deadspin.com' => 'PHP/5.2',\r | |
368 | 'kotaku.com' => 'PHP/5.2',\r | |
369 | 'jezebel.com' => 'PHP/5.2',\r | |
370 | 'io9.com' => 'PHP/5.2',\r | |
371 | 'jalopnik.com' => 'PHP/5.2',\r | |
372 | 'gizmodo.com' => 'PHP/5.2',\r | |
373 | '.wikipedia.org' => 'Mozilla/5.2',\r | |
374 | '.fok.nl' => 'Googlebot/2.1',\r | |
375 | 'getpocket.com' => 'PHP/5.2'\r | |
376 | );\r | |
377 | \r | |
378 | // URL Rewriting\r | |
379 | // ----------------------\r | |
380 | // Currently allows simple string replace of URLs.\r | |
381 | // Useful for rewriting certain URLs to point to a single page\r | |
382 | // or HTML view. Although using the single_page_link site config\r | |
383 | // instruction is the preferred way to do this, sometimes, as\r | |
384 | // with Google Docs URLs, it's not possible.\r | |
385 | // Note: this might move to the site config file at some point.\r | |
386 | $options->rewrite_url = array(\r | |
387 | // Rewrite public Google Docs URLs to point to HTML view:\r | |
388 | // if a URL contains docs.google.com, replace /Doc? with /View?\r | |
389 | 'docs.google.com' => array('/Doc?' => '/View?'),\r | |
390 | 'tnr.com' => array('tnr.com/article/' => 'tnr.com/print/article/'),\r | |
391 | '.m.wikipedia.org' => array('.m.wikipedia.org' => '.wikipedia.org'),\r | |
392 | 'm.vanityfair.com' => array('m.vanityfair.com' => 'www.vanityfair.com')\r | |
393 | );\r | |
394 | \r | |
395 | // Content-Type exceptions\r | |
396 | // -----------------------\r | |
397 | // Here you can define different actions based\r | |
398 | // on the Content-Type header returned by server.\r | |
399 | // MIME type as key, action as value.\r | |
400 | // Valid actions:\r | |
401 | // * 'exclude' - exclude this item from the result\r | |
402 | // * 'link' - create HTML link to the item\r | |
403 | $options->content_type_exc = array(\r | |
404 | 'application/pdf' => array('action'=>'link', 'name'=>'PDF'),\r | |
405 | 'image' => array('action'=>'link', 'name'=>'Image'),\r | |
406 | 'audio' => array('action'=>'link', 'name'=>'Audio'),\r | |
407 | 'video' => array('action'=>'link', 'name'=>'Video')\r | |
408 | );\r | |
409 | \r | |
410 | // Cache directory level\r | |
411 | // ----------------------\r | |
412 | // Spread cache files over different directories (only used if caching is enabled).\r | |
413 | // Used to prevent large number of files in one directory.\r | |
414 | // This corresponds to Zend_Cache's hashed_directory_level\r | |
415 | // see http://framework.zend.com/manual/en/zend.cache.backends.html\r | |
416 | // It's best not to change this if you're unsure.\r | |
417 | $options->cache_directory_level = 0;\r | |
418 | \r | |
419 | // Cache cleanup\r | |
420 | // -------------\r | |
421 | // 0 = script will not clean cache (rename cachecleanup.php and use it for scheduled (e.g. cron) cache cleanup)\r | |
422 | // 1 = clean cache everytime the script runs (not recommended)\r | |
423 | // 100 = clean cache roughly once every 100 script runs\r | |
424 | // x = clean cache roughly once every x script runs\r | |
425 | // ...you get the idea :)\r | |
426 | $options->cache_cleanup = 100;\r | |
427 | \r | |
428 | /////////////////////////////////////////////////\r | |
429 | /// DO NOT CHANGE ANYTHING BELOW THIS ///////////\r | |
430 | /////////////////////////////////////////////////\r | |
431 | \r | |
432 | if (!defined('_FF_FTR_VERSION')) define('_FF_FTR_VERSION', '3.2');\r | |
433 | \r | |
434 | if (basename(__FILE__) == 'config.php') {\r | |
435 | if (file_exists(dirname(__FILE__).'/custom_config.php')) {\r | |
436 | require_once dirname(__FILE__).'/custom_config.php';\r | |
437 | }\r | |
438 | \r | |
439 | // check for environment variables - often used on cloud platforms\r | |
440 | // environment variables should be prefixed with 'ftr_', e.g.\r | |
441 | // ftr_max_entries: 1\r | |
442 | // will set the max_entries value to 1.\r | |
443 | foreach ($options as $_key=>&$_val) {\r | |
444 | $_key = "ftr_$_key";\r | |
445 | if (($_env = getenv($_key)) !== false) {\r | |
446 | if (is_array($_val)) {\r | |
447 | if ($_key === 'ftr_admin_credentials') {\r | |
448 | $_val = array_combine(array('username', 'password'), array_map('trim', explode(':', $_env, 2)));\r | |
449 | if ($_val === false) $_val = array('username'=>'admin', 'password'=>'');\r | |
450 | }\r | |
451 | } elseif ($_env === 'true' || $_env === 'false') {\r | |
452 | $_val = ($_env === 'true');\r | |
453 | } elseif (is_numeric($_env)) {\r | |
454 | $_val = (int)$_env;\r | |
455 | } else { // string\r | |
456 | $_val = $_env;\r | |
457 | }\r | |
458 | }\r | |
459 | }\r | |
460 | unset($_key, $_val, $_env);\r | |
461 | } |