Joomla Platform  13.1
Documentation des API du framework Joomla Platform
 Tout Classes Espaces de nommage Fichiers Fonctions Variables Pages
formattedtext.php
Aller à la documentation de ce fichier.
1 <?php
2 /**
3  * @package Joomla.Platform
4  * @subpackage Log
5  *
6  * @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
7  * @license GNU General Public License version 2 or later; see LICENSE
8  */
9 
10 defined('JPATH_PLATFORM') or die;
11 
12 jimport('joomla.filesystem.folder');
13 
14 /**
15  * Joomla! Formatted Text File Log class
16  *
17  * This class is designed to use as a base for building formatted text files for output. By
18  * default it emulates the Syslog style format output. This is a disk based output format.
19  *
20  * @package Joomla.Platform
21  * @subpackage Log
22  * @since 11.1
23  */
25 {
26  /**
27  * @var resource The file pointer for the log file.
28  * @since 11.1
29  */
30  protected $file;
31 
32  /**
33  * @var string The format for which each entry follows in the log file. All fields must be named
34  * in all caps and be within curly brackets eg. {FOOBAR}.
35  * @since 11.1
36  */
37  protected $format = '{DATETIME} {PRIORITY} {CATEGORY} {MESSAGE}';
38 
39  /**
40  * @var array The parsed fields from the format string.
41  * @since 11.1
42  */
43  protected $fields = array();
44 
45  /**
46  * @var string The full filesystem path for the log file.
47  * @since 11.1
48  */
49  protected $path;
50 
51  /**
52  * Constructor.
53  *
54  * @param array &$options Log object options.
55  *
56  * @since 11.1
57  */
58  public function __construct(array &$options)
59  {
60  // Call the parent constructor.
61  parent::__construct($options);
62 
63  // The name of the text file defaults to 'error.php' if not explicitly given.
64  if (empty($this->options['text_file']))
65  {
66  $this->options['text_file'] = 'error.php';
67  }
68 
69  // The name of the text file path defaults to that which is set in configuration if not explicitly given.
70  if (empty($this->options['text_file_path']))
71  {
72  $this->options['text_file_path'] = JFactory::getConfig()->get('log_path');
73  }
74 
75  // False to treat the log file as a php file.
76  if (empty($this->options['text_file_no_php']))
77  {
78  $this->options['text_file_no_php'] = false;
79  }
80 
81  // Build the full path to the log file.
82  $this->path = $this->options['text_file_path'] . '/' . $this->options['text_file'];
83 
84  // Use the default entry format unless explicitly set otherwise.
85  if (!empty($this->options['text_entry_format']))
86  {
87  $this->format = (string) $this->options['text_entry_format'];
88  }
89 
90  // Build the fields array based on the format string.
91  $this->parseFields();
92  }
93 
94  /**
95  * Destructor.
96  *
97  * @since 11.1
98  */
99  public function __destruct()
100  {
101  if (is_resource($this->file))
102  {
103  fclose($this->file);
104  }
105  }
106 
107  /**
108  * Method to add an entry to the log.
109  *
110  * @param JLogEntry $entry The log entry object to add to the log.
111  *
112  * @return boolean True on success.
113  *
114  * @since 11.1
115  * @throws RuntimeException
116  */
117  public function addEntry(JLogEntry $entry)
118  {
119  // Initialise the file if not already done.
120  if (!is_resource($this->file))
121  {
122  $this->initFile();
123  }
124 
125  // Set some default field values if not already set.
126  if (!isset($entry->clientIP))
127  {
128 
129  // Check for proxies as well.
130  if (isset($_SERVER['REMOTE_ADDR']))
131  {
132  $entry->clientIP = $_SERVER['REMOTE_ADDR'];
133  }
134  elseif (isset($_SERVER['HTTP_X_FORWARDED_FOR']))
135  {
136  $entry->clientIP = $_SERVER['HTTP_X_FORWARDED_FOR'];
137  }
138  elseif (isset($_SERVER['HTTP_CLIENT_IP']))
139  {
140  $entry->clientIP = $_SERVER['HTTP_CLIENT_IP'];
141  }
142  }
143 
144  // If the time field is missing or the date field isn't only the date we need to rework it.
145  if ((strlen($entry->date) != 10) || !isset($entry->time))
146  {
147 
148  // Get the date and time strings in GMT.
149  $entry->datetime = $entry->date->toISO8601();
150  $entry->time = $entry->date->format('H:i:s', false);
151  $entry->date = $entry->date->format('Y-m-d', false);
152  }
153 
154  // Get a list of all the entry keys and make sure they are upper case.
155  $tmp = array_change_key_case(get_object_vars($entry), CASE_UPPER);
156 
157  // Decode the entry priority into an English string.
158  $tmp['PRIORITY'] = $this->priorities[$entry->priority];
159 
160  // Fill in field data for the line.
161  $line = $this->format;
162 
163  foreach ($this->fields as $field)
164  {
165  $line = str_replace('{' . $field . '}', (isset($tmp[$field])) ? $tmp[$field] : '-', $line);
166  }
167 
168  // Write the new entry to the file.
169  if (!fwrite($this->file, $line . "\n"))
170  {
171  throw new RuntimeException('Cannot write to log file.');
172  }
173  }
174 
175  /**
176  * Method to generate the log file header.
177  *
178  * @return string The log file header
179  *
180  * @since 11.1
181  */
182  protected function generateFileHeader()
183  {
184  $head = array();
185 
186  // Build the log file header.
187 
188  // If the no php flag is not set add the php die statement.
189  if (empty($this->options['text_file_no_php']))
190  {
191  // Blank line to prevent information disclose: https://bugs.php.net/bug.php?id=60677
192  $head[] = '#';
193  $head[] = '#<?php die(\'Forbidden.\'); ?>';
194  }
195  $head[] = '#Date: ' . gmdate('Y-m-d H:i:s') . ' UTC';
196  $head[] = '#Software: ' . JPlatform::getLongVersion();
197  $head[] = '';
198 
199  // Prepare the fields string
200  $head[] = '#Fields: ' . strtolower(str_replace('}', '', str_replace('{', '', $this->format)));
201  $head[] = '';
202 
203  return implode("\n", $head);
204  }
205 
206  /**
207  * Method to initialise the log file. This will create the folder path to the file if it doesn't already
208  * exist and also get a new file header if the file doesn't already exist. If the file already exists it
209  * will simply open it for writing.
210  *
211  * @return void
212  *
213  * @since 11.1
214  * @throws RuntimeException
215  */
216  protected function initFile()
217  {
218  // If the file doesn't already exist we need to create it and generate the file header.
219  if (!is_file($this->path))
220  {
221 
222  // Make sure the folder exists in which to create the log file.
223  JFolder::create(dirname($this->path));
224 
225  // Build the log file header.
226  $head = $this->generateFileHeader();
227  }
228  else
229  {
230  $head = false;
231  }
232 
233  // Open the file for writing (append mode).
234  if (!$this->file = fopen($this->path, 'a'))
235  {
236  throw new RuntimeException('Cannot open file for writing log');
237  }
238  if ($head)
239  {
240  if (!fwrite($this->file, $head))
241  {
242  throw new RuntimeException('Cannot fput file for log');
243  }
244  }
245  }
246 
247  /**
248  * Method to parse the format string into an array of fields.
249  *
250  * @return void
251  *
252  * @since 11.1
253  */
254  protected function parseFields()
255  {
256  $this->fields = array();
257  $matches = array();
258 
259  // Get all of the available fields in the format string.
260  preg_match_all("/{(.*?)}/i", $this->format, $matches);
261 
262  // Build the parsed fields list based on the found fields.
263  foreach ($matches[1] as $match)
264  {
265  $this->fields[] = strtoupper($match);
266  }
267  }
268 }