source: trunk/includes/system.php@ 841

Last change on this file since 841 was 841, checked in by chronos, 9 years ago
  • Modified: Improved language switching using language code in URL. This is more search engine friendly as each language have own fixed URL.
  • Property svn:executable set to *
File size: 20.4 KB
Line 
1<?php
2
3class Core extends Application
4{
5 var $Config;
6 var $PathItems;
7 var $Menu;
8 var $DoNotShowPage;
9 var $OnPageNotFound;
10 var $Pages;
11
12 function __construct()
13 {
14 parent::__construct();
15 $this->Config = array();
16 $this->Menu = array();
17 $this->RSSChannels = array();
18 $this->DoNotShowPage = false;
19 $this->OnPageNotFound = array();
20 $this->Pages = array();
21 }
22
23 function Init()
24 {
25 global $GlobalLocaleManager;
26
27 $this->Database->Connect($this->Config['Database']['Host'],
28 $this->Config['Database']['User'], $this->Config['Database']['Password'],
29 $this->Config['Database']['Database']);
30 $this->Database->charset($this->Config['Database']['Charset']);
31 $this->Database->ShowSQLQuery = $this->Config['Web']['ShowSQLQuery'];
32 $this->Database->ShowSQLError = $this->Config['Web']['ShowSQLError'];
33 $this->Database->LogSQLQuery = $this->Config['Web']['LogSQLQuery'];
34
35 $this->LocaleManager = new LocaleManager($this);
36 $this->LocaleManager->Dir = dirname(dirname(__FILE__)).'/locale';
37 $this->LocaleManager->Available = array(
38 'cs' => array('Code' => 'cs', 'Title' => 'Česky'),
39 'en' => array('Code' => 'en', 'Title' => 'English'),
40 );
41 $GlobalLocaleManager = $this->LocaleManager;
42 $this->LinkLocaleExceptions = array('images', 'style', 'tmp');
43
44 $this->PathItems = ProcessURL();
45
46 // Detect interface locale
47 $this->LocaleManager->DefaultLangCode = $this->Config['Web']['Locale'];
48 $this->LocaleManager->LangCode = $this->LocaleManager->DefaultLangCode;
49 if(count($this->PathItems) > 0)
50 {
51 $NewLangCode = $this->PathItems[0];
52 if(array_key_exists($NewLangCode, $this->LocaleManager->Available)) {
53 array_shift($this->PathItems);
54 $this->LocaleManager->LangCode = $NewLangCode;
55 }
56 }
57 $this->LocaleManager->LoadLocale($this->LocaleManager->LangCode);
58
59 $this->Menu = array
60 (
61 /* array(
62 'Title' => T('Files'),
63 'Hint' => 'Stahování různých pomocných souborů a programů',
64 'Link' => $this->Link('/download.php'),
65 'Permission' => LICENCE_ANONYMOUS,
66 'Icon' => '',
67 ),
68 */
69 array(
70 'Title' => T('Instructions'),
71 'Hint' => 'Informace k překladu hry',
72 'Link' => $this->Link('/info.php'),
73 'Permission' => LICENCE_ANONYMOUS,
74 'Icon' => '',
75 ),
76 array(
77 'Title' => T('Data source'),
78 'Hint' => 'Informace o překladových skupinách',
79 'Link' => $this->Link('/TranslationList.php?action=grouplist'),
80 'Permission' => LICENCE_ANONYMOUS,
81 'Icon' => '',
82 ),
83 array(
84 'Title' => T('Presentation'),
85 'Hint' => 'Prezentace a motivace překladu',
86 'Link' => $this->Link('/promotion.php'),
87 'Permission' => LICENCE_ANONYMOUS,
88 'Icon' => '',
89 ),
90 array(
91 'Title' => T('IRC chat'),
92 'Hint' => 'IRC chat pro překladatele',
93 'Link' => 'http://embed.mibbit.com/?server=game.zdechov.net%3A6667&amp;channel=%23wowpreklad&amp;forcePrompt=true&amp;charset=utf-8',
94 'Permission' => LICENCE_ANONYMOUS,
95 'Icon' => '',
96 ),
97 array(
98 'Title' => T('Administration'),
99 'Hint' => 'Volby pro správu',
100 'Link' => $this->Link('/admin/'),
101 'Permission' => LICENCE_ADMIN,
102 'Icon' => '',
103 ),
104 );
105 }
106
107 function Run()
108 {
109 global $ScriptStartTime, $TranslationTree, $StopAfterUpdateManager, $Config,
110 $UpdateManager, $DatabaseRevision;
111
112 $this->Config = $Config;
113 $ScriptStartTime = GetMicrotime();
114
115 if(GetRemoteAddress() != '') session_start();
116
117 if(!isset($this->Config)) die('Systém není nainstalován. Pokračujte v instalaci <a href="admin/install.php">zde</a>.');
118 date_default_timezone_set($this->Config['Web']['Timezone']);
119
120 $this->Init();
121
122 // Check database persistence structure
123 $UpdateManager = new UpdateManager();
124 $UpdateManager->Database = $this->Database;
125 $UpdateManager->Revision = $DatabaseRevision;
126 if(!$UpdateManager->IsInstalled()) die('Systém vyžaduje instalaci databáze.');
127 if(!$UpdateManager->IsUpToDate()) die('Systém vyžaduje aktualizaci databáze.');
128
129 // SQL injection hack protection
130 foreach($_POST as $Index => $Item)
131 {
132 if(is_array($_POST[$Index]))
133 foreach($_POST[$Index] as $Index2 => $Item2) $_POST[$Index][$Index2] = addslashes($Item2);
134 else $_POST[$Index] = addslashes($_POST[$Index]);
135 }
136 foreach($_GET as $Index => $Item) $_GET[$Index] = addslashes($_GET[$Index]);
137
138 // TODO: Global initialized variable should be removed
139 $TranslationTree = GetTranslationTree();
140
141 // Initialize application modules
142 $this->ModuleManager->RegisterModule(new ModuleError($this));
143 $this->ModuleManager->Modules['Error']->ErrorHandler->ShowError = $this->Config['Web']['ShowPHPError'];
144 $this->ModuleManager->RegisterModule(new ModuleLog($this));
145 $this->ModuleManager->RegisterModule(new ModuleUser($this));
146 $this->ModuleManager->RegisterModule(new ModuleAoWoW($this));
147 $this->ModuleManager->RegisterModule(new ModuleReferrer($this));
148 $this->ModuleManager->Modules['Referrer']->Excludes[] = $this->Config['Web']['Host'];
149 $this->ModuleManager->RegisterModule(new ModuleTeam($this));
150 $this->ModuleManager->RegisterModule(new ModuleDictionary($this));
151 $this->ModuleManager->RegisterModule(new ModuleTranslation($this));
152 $this->ModuleManager->RegisterModule(new ModuleImport($this));
153 $this->ModuleManager->RegisterModule(new ModuleExport($this));
154 $this->ModuleManager->RegisterModule(new ModuleServer($this));
155 $this->ModuleManager->RegisterModule(new ModuleClientVersion($this));
156 $this->ModuleManager->RegisterModule(new ModuleShoutBox($this));
157 $this->ModuleManager->RegisterModule(new ModuleNews($this));
158 $this->ModuleManager->RegisterModule(new ModuleWiki($this));
159 $this->ModuleManager->RegisterModule(new ModuleSearch($this));
160 $this->ModuleManager->RegisterModule(new ModuleFrontPage($this));
161 $this->ModuleManager->RegisterModule(new ModuleDownload($this));
162 $this->ModuleManager->RegisterModule(new ModuleForum($this));
163 $this->ModuleManager->RegisterModule(new ModuleRedirection($this));
164 $this->ModuleManager->FileName = dirname(__FILE__).'/../Config/ModulesConfig.php';
165 // TODO: Allow control from web which modules should be installed
166 $this->ModuleManager->InstallAll();
167 $this->ModuleManager->StartAll();
168
169 $this->BaseView = new BaseView($this);
170 if($this->DoNotShowPage == false)
171 {
172 $this->ShowPage();
173 }
174 }
175
176 function GetMicrotime()
177 {
178 list($Usec, $Sec) = explode(' ', microtime());
179 return ((float)$Usec + (float)$Sec);
180 }
181
182 function Link($Target)
183 {
184 $Remaining = substr($Target, count($this->Config['Web']['BaseURL']));
185 $TargetParts = explode('/', $Remaining);
186 if(count($TargetParts) > 0)
187 {
188 if(in_array($TargetParts[0], $this->LinkLocaleExceptions))
189 {
190 return($this->Config['Web']['BaseURL'].$Target);
191 }
192 }
193 return($this->LinkLocale($Target));
194 }
195
196 function LinkLocale($Target, $Locale = '')
197 {
198 if($Locale == '') $Locale = $this->LocaleManager->LangCode;
199 if($Locale == $this->LocaleManager->DefaultLangCode)
200 return($this->Config['Web']['BaseURL'].$Target);
201 return($this->Config['Web']['BaseURL'].'/'.$Locale.$Target);
202 }
203
204 function RegisterPage($Path, $Handler)
205 {
206 if(is_array($Path))
207 {
208 $Page = &$this->Pages;
209 $LastKey = array_pop($Path);
210 foreach($Path as $PathItem)
211 {
212 $Page = &$Page[$PathItem];
213 }
214 if(!is_array($Page)) $Page = array('' => $Page);
215 $Page[$LastKey] = $Handler;
216 } else $this->Pages[$Path] = $Handler;
217 }
218
219 function RegisterMenuItem($MenuItem, $Pos = NULL)
220 {
221 if(is_null($Pos)) $this->Menu[] = $MenuItem;
222 else {
223 array_splice($this->Menu, $Pos, 0, array($MenuItem));
224 }
225 }
226
227 function SearchPage($PathItems, $Pages)
228 {
229 if(count($PathItems) == 0) $PathItems = array('');
230 $PathItem = $PathItems[0];
231 if(array_key_exists($PathItem, $Pages))
232 {
233 if(is_array($Pages[$PathItem]))
234 {
235 array_shift($PathItems);
236 return($this->SearchPage($PathItems, $Pages[$PathItem]));
237 } else
238 {
239 if(count($PathItems) == 1) return($Pages[$PathItem]);
240 else return(''); // Unexpected subpages
241 }
242 } else return('');
243 }
244
245 function PageNotFound()
246 {
247 // Send correct HTTP status code to signal unknown page
248 if(array_key_exists('SERVER_PROTOCOL', $_SERVER))
249 Header($_SERVER['SERVER_PROTOCOL'].' 404 Not Found');
250 if(array_key_exists('HTTP_REFERER', $_SERVER)) $Referer = ' Referer: '.$_SERVER['HTTP_REFERER'];
251 else $Referer = '';
252 if(isset($this->ModuleManager->Modules['Log']))
253 $this->ModuleManager->Modules['Log']->WriteLog('Stránka "'.
254 implode('/', $this->PathItems).'" nenalezena'.$Referer, LOG_TYPE_PAGE_NOT_FOUND);
255 return(ShowMessage(sprintf(T('Page "%s" not found'), implode('/', $this->PathItems)), MESSAGE_CRITICAL));
256 }
257
258 function ShowPage()
259 {
260 $Output = '';
261
262 /* @var $Page Page */
263 $ClassName = $this->SearchPage($this->PathItems, $this->Pages);
264 if(($ClassName != '') and (class_exists($ClassName)))
265 {
266 $Page = new $ClassName($this);
267 $Output = $Page->GetOutput();
268 $this->BaseView->Title = $Page->Title;
269 if($Page->RawPage == false) $Output = $this->BaseView->ShowPage($Output);
270 } else {
271 $Output2 = '';
272 if((count($this->OnPageNotFound) == 2)
273 and method_exists($this->OnPageNotFound[0], $this->OnPageNotFound[1]))
274 $Output2 = call_user_func_array($this->OnPageNotFound, array());
275 if($Output2 != '') $Output .= $this->BaseView->ShowPage($Output2);
276 else {
277 $Output = $this->PageNotFound();
278 $this->BaseView->Title = T('Page not found');
279 $Output = $this->BaseView->ShowPage($Output);
280 }
281 }
282 echo($Output);
283 }
284}
285
286class BaseView extends View
287{
288 var $Title;
289
290 function ShowLocaleSelector()
291 {
292 //$Output .= ' <form action="?setlocale" method="get">';
293 $Output = ' <select onchange="window.location=this.value">';
294 foreach($this->System->LocaleManager->Available as $Locale)
295 {
296 $Remaining = substr($_SERVER["REQUEST_URI"], strlen($this->System->Config['Web']['BaseURL']));
297 if(substr($Remaining, 1, strlen($Locale['Code'].'/')) == $this->System->LocaleManager->LangCode.'/')
298 $Remaining = substr($Remaining, strlen('/'.$Locale['Code']));
299 if($Locale['Code'] == $this->System->LocaleManager->CurrentLocale->Texts->Code) $Selected = ' selected="selected"';
300 else $Selected = '';
301 $URL = $this->System->LinkLocale($Remaining, $Locale['Code']);
302 $Output .= '<option title="" value="'.$URL.'"'.$Selected.' onchange="this.form.submit()">'.$Locale['Title'].'</option>';
303 }
304 $Output .= '</select><noscript><span><input type="submit" value="Submit"/></span></noscript>';
305
306 return($Output);
307 }
308
309 function ShowTopBar()
310 {
311 $Output = '<div class="Menu">';
312 if(!$this->System->User->Licence(LICENCE_USER))
313 $Output .= '<div class="advert">'.$this->System->Config['Web']['Advertisement'].'</div>';
314 $Output .= '<span class="MenuItem"></span><span class="MenuItem2">';
315 if($this->System->User->Licence(LICENCE_USER))
316 {
317 //$DbResult =$this->Database->query('SELECT `Id`, `Name` FROM `Team` WHERE `Id`='.$this->System->User->Team);
318 //$Team = $DbResult->fetch_assoc();
319 //$Output .= ''<span class="MenuItem">Moje překlady: <a href="">Dokončené</a> <a href="">Rozpracované</a> <a href="">Exporty</a> Tým: <a href="">'.$Team['name'].'</a></span>';
320 $Output .= $this->System->User->Name.' <a href="'.$this->System->Link('/?action=logout').'">'.T('Logout').'</a>'.
321 ' <a href="'.$this->System->Link('/user.php?user='.$this->System->User->Id).'">'.T('My page').'</a>'.
322 ' <a href="'.$this->System->Link('/Options.php').'">'.T('Options').'</a>'.
323 ' <a title="Vámi přeložené texty" href="'.$this->System->Link('/TranslationList.php?user='.
324 $this->System->User->Id.'&amp;group=0&amp;state=2&amp;text=&amp;entry=').'">'.T('Translated').'</a>'.
325 ' <a title="Vaše rozpracované text" href="'.$this->System->Link('/TranslationList.php?user='.
326 $this->System->User->Id.'&amp;group=0&amp;state=3&amp;text=&amp;entry=').'">'.T('Unfinished').'</a>'.
327 ' <a title="Nikým nepřeložené texty" href="'.
328 $this->System->Link('/TranslationList.php?user=0&amp;group=0&amp;state=1&amp;text=&amp;entry=').'">'.T('Untranslated').'</a>';
329 } else
330 {
331 $Output .= '<a href="'.$this->System->Link('/login/').'">'.T('Login').'</a>&nbsp;'.
332 '<a href="'.$this->System->Link('/registrace.php').'">'.T('Registration').'</a>';
333 }
334 $Output .= $this->ShowLocaleSelector();
335 //$Output .= '</form>';
336 $Output .= '</span></div>';
337 return($Output);
338 }
339
340 function ShowLoginBox()
341 {
342 $Output = '';
343 if($this->System->User->Licence(LICENCE_USER))
344 {
345 // $Output .= 'Jste přihlášen jako: <b>'.$tUser->Id.'</b> <a href="index.php?Logout">Odhlásit</a>';
346 } else
347 {
348 $Output .= '<strong>'.T('Login').':</strong>
349 <form action="" method="post">
350 <table>
351 <tr>
352 <td><input type="text" name="LoginUser" size="13" /></td>
353 </tr>
354 <tr>
355 <td><input type="password" name="LoginPass" size="13" /></td>
356 </tr>
357 <tr>
358 <th><input type="submit" value="'.T('Do login').'" /></th>
359 </tr>
360 </table>
361 </form>';
362 }
363 return($Output);
364 }
365
366 function ShowSearchBox()
367 {
368 $Output = '<strong>'.T('Search').':</strong>'.
369 '<form action="'.$this->System->Link('/search/').'" method="get"><div>'.
370 '<table>'.
371 '<tr>'.
372 '<td><input type="text" name="text" size="13" /></td>'.
373 '</tr>'.
374 '<tr>'.
375 '<th><input type="submit" value="'.T('Do search').'" /></th>'.
376 '</tr>'.
377 '</table></div>'.
378 '</form>';
379 return($Output);
380 }
381
382 function ShowMainMenu()
383 {
384 $Output = '<strong>'.T('Menu').':</strong>'.
385 '<div class="verticalmenu"><ul>';
386 foreach($this->System->Menu as $MenuItem)
387 if($this->System->User->Licence($MenuItem['Permission']))
388 {
389 if(isset($MenuItem['Click'])) $OnClick = ' onclick="'.$MenuItem['Click'].'"';
390 else $OnClick = '';
391 if($MenuItem['Icon'] != '') $Icon = '<img src="'.$this->System->Link('/images/menu/'.$MenuItem['Icon']).'"/>';
392 else $Icon = '';
393 $Output .= '<li>'.$Icon.'<a class="verticalmenua" title="'.$MenuItem['Hint'].'" href="'.
394 $MenuItem['Link'].'"'.$OnClick.'>'.$MenuItem['Title'].'</a></li>';
395 }
396 $Output .= '</ul></div>';
397 return($Output);
398 }
399
400 function ShowTranslatedMenu()
401 {
402 global $TranslationTree;
403
404 $Output = '<strong>'.T('Translate groups').':</strong><br /><div id="TranslationMenu">';
405 $DbResult = $this->System->Database->select('Group', '`Id`, `Name`', '1 ORDER BY `Name`');
406 while($Group = $DbResult->fetch_assoc())
407 {
408 $Output .= '<div id="menuitem-group'.$Group['Id'].'" onmouseover="show(\'group'.$Group['Id'].'\')" onmouseout="hide(\'group'.$Group['Id'].'\')">'.
409 '<a href="'.$this->System->Link('/TranslationList.php?group='.$Group['Id'].'&amp;action=filter').'">'.str_replace(' ','&nbsp;',$Group['Name']).'</a></div>'.
410 '<div id="group'.$Group['Id'].'" class="hidden-menu-item" onmouseover="show(\'group'.$Group['Id'].'\')" onmouseout="hide(\'group'.$Group['Id'].'\')">';
411 $Output .= '&nbsp;<a title="Zde můžete začít překládat" href="'.$this->System->Link('/TranslationList.php?group='.$Group['Id'].'&amp;state=1&amp;user=0&amp;entry=&amp;text=').'">'.T('Untranslated').'</a><br />'.
412 '&nbsp;<a title="Přeložené texty, můžete zde hlasovat, nebo opravovat překlady" href="'.$this->System->Link('/TranslationList.php?group='.$Group['Id'].'&amp;state=2&amp;user=0&amp;entry=&amp;text=').'">'.T('Translated').'</a><br />';
413 if($this->System->User->Licence(LICENCE_USER))
414 {
415 $Output .= '&nbsp;<a title="'.T('Unfinished translations').'" href="'.$this->System->Link('/TranslationList.php?group='.$Group['Id'].'&amp;state=3').'">'.T('Unfinished').'</a><br />
416 &nbsp;<a title="Všechny překlady, které jste přeložil" href="'.$this->System->Link('/TranslationList.php?group='.$Group['Id'].'&amp;state=1&amp;user='.$this->System->User->Id).'&amp;entry=&amp;text=">'.T('Own').'</a><br />';
417 }
418 $Output .= '&nbsp;<a title="'.T('Compose special filter').'" href="'.$this->System->Link('/TranslationList.php?group='.$Group['Id'].'&amp;action=filter').'">'.T('Filter').'</a><br />';
419 $Output .= '</div>';
420 }
421 $Output .= '</div>';
422 return($Output);
423 }
424
425 function ShowHeader()
426 {
427 $Output = ''.
428 '<!DOCTYPE html>'.
429 '<html>'.
430 '<head>'.
431 '<meta http-equiv="content-type" content="text/html; charset='.$this->System->Config['Web']['Charset'].'" />'.
432 '<meta name="keywords" content="'.$this->System->Config['Web']['Keywords'].'" />'.
433 '<meta name="description" content="'.$this->System->Config['Web']['Description'].'" />'.
434 '<meta name="robots" content="all" />'.
435 '<link rel="stylesheet" href="'.$this->System->Link('/style/style.css').'" type="text/css" media="all" />'.
436 '<script type="text/javascript" src="'.$this->System->Link('/style/global.js').'"></script>'.
437 '<link rel="shortcut icon" href="'.$this->System->Link('/images/favicon.ico').'" />';
438 $Output .= $this->System->ModuleManager->Modules['News']->ShowRSSHeader();
439 $Title = $this->System->Config['Web']['Title'];
440 if($this->Title != '') $Title = $this->Title.' - '.$Title;
441 $Output .= '<title>'.$Title.'</title>'.
442 '</head><body>';
443
444 $Output .= $this->ShowTopBar();
445 $Output .= '<table class="page"><tr><td class="menu">';
446 $Output .= $this->ShowMainMenu();
447 $Output .= $this->System->ModuleManager->Modules['User']->ShowOnlineList();
448 $Output .= '<br />';
449 $Output .= $this->ShowSearchBox();
450
451 $Output .= '</td><td id="border-left"></td><td class="content">';
452 return($Output);
453 }
454
455 function ShowFooter()
456 {
457 global $ScriptStartTime, $Revision, $ReleaseTime;
458
459 $ScriptGenerateDuration = round(GetMicrotime() - $ScriptStartTime, 2);
460
461 $Output = '</td>'.
462 '<td class="menu2">';
463 $Output .= $this->ShowTranslatedMenu();
464 $Output .= '</td>'.
465 '</tr><tr>'.
466 '<td colspan="4" class="page-bottom">'.T('Version').': '.$Revision.' ('.HumanDate($ReleaseTime).')'.
467 ' &nbsp; <a href="http://svn.zdechov.net/trac/wowpreklad/browser/trunk">'.T('Source code').'</a> &nbsp; '.
468 '<a href="http://svn.zdechov.net/trac/wowpreklad/log/trunk?verbose=on">'.T('Changelog').'</a> &nbsp; '.
469 $this->System->Config['Web']['WebCounter'];
470
471 $Output .= '</td></tr>';
472 if($this->System->Config['Web']['ShowRuntimeInfo'] == true)
473 $Output .= '<tr><td colspan="3" style="text-align: center;">'.T('Generating duration').': '.
474 $ScriptGenerateDuration.' s / '.ini_get('max_execution_time').' s &nbsp;&nbsp; '.T('Used memory').': '.
475 HumanSize(memory_get_peak_usage(FALSE)).' / '.ini_get('memory_limit').'B &nbsp;&nbsp; <a href="http://validator.w3.org/check?uri='.
476 htmlentities('http://'.$_SERVER['HTTP_HOST'].GetRequestURI().'?'.$_SERVER['QUERY_STRING']).'">HTML validator</a></td></tr>';
477 $Output .= '</table>'.
478 '</body>'.
479 '</html>';
480 return($Output);
481 }
482
483 function ShowPage($Content)
484 {
485 $Output = $this->ShowHeader().$Content.$this->ShowFooter();
486 if($this->System->Config['Web']['FormatOutput'])
487 $Output = $this->FormatOutput($Output);
488 return($Output);
489 }
490
491 function FormatOutput($s)
492 {
493 $out = '';
494 $nn = 0;
495 $n = 0;
496 while($s != '')
497 {
498 $start = strpos($s, '<');
499 $end = strpos($s, '>');
500 if($start != 0)
501 {
502 $end = $start - 1;
503 $start = 0;
504 }
505 $line = trim(substr($s, $start, $end + 1));
506 if(strlen($line) > 0)
507 if($line[0] == '<')
508 {
509 if($s[$start + 1] == '/')
510 {
511 $n = $n - 2;
512 $nn = $n;
513 } else
514 {
515 if(strpos($line, ' ')) $cmd = substr($line, 1, strpos($line, ' ') - 1);
516 else $cmd = substr($line, 1, strlen($line) - 2);
517 //echo('['.$cmd.']');
518 if(strpos($s, '</'.$cmd.'>')) $n = $n + 2;
519 }
520 }// else $line = '['.$line.']';
521 //if($line != '') echo(htmlspecialchars(str_repeat(' ',$nn).$line."\n"));
522 if($nn < 0) $nn = 0;
523 if($line != '') $out .= (str_repeat(' ', $nn).$line."\n");
524 $s = substr($s, $end + 1, strlen($s));
525 $nn = $n;
526 }
527 return($out);
528 }
529}
Note: See TracBrowser for help on using the repository browser.