1 <?php # vim:ts=2:sw=2:et:
2 /* For licensing and copyright terms, see the file named LICENSE */
4 include '../inc/common.php';
5 #error_reporting(E_ALL | E_NOTICE);
7 $pi = mtrack_get_pathinfo();
12 $edit = isset($_REQUEST['edit']) ? (int)$_REQUEST['edit'] : null;
16 function is_content_conflicted($content)
18 if (preg_match("/^(<+)\s+(mine|theirs|original)\s*$/m", $content)) {
23 function normalize_text($text) {
24 return rtrim($text) . "\n";
29 $doc = MTrackWikiItem::loadByPageName($pi);
31 MTrackACL::requireAnyRights("wiki:$doc->pagename",
32 $edit ? 'modify' : 'read');
34 MTrackACL::requireAnyRights("wiki:$pi",
35 $edit ? 'modify' : 'read');
37 if ($doc === null && $edit) {
38 $doc = new MTrackWikiItem($pi);
39 $doc->content = " = $pi =\n";
42 if ($_SERVER['REQUEST_METHOD'] == 'POST') {
44 if (isset($_POST['cancel'])) {
45 header("Location: ${ABSWEB}wiki.php/$pi");
48 if (!MTrackCaptcha::check('wiki')) {
49 $message = 'CAPTCHA failed, please try again';
50 } else if (isset($_POST['save'])) {
51 /* to avoid annoying "you lose because someone else edited" errors,
52 * we compute the diff from the original content we had, and apply
53 * that to the current content of the object */
57 $orig = base64_decode($_POST['orig']);
58 $content = $_POST['content'];
60 /* for consistency, we always want a newline at the end, otherwise
61 * we can end up with some weird output from diff3 */
62 $orig = normalize_text($orig);
63 $content = normalize_text($content);
64 $doc->content = normalize_text($doc->content);
65 $conflicted = is_content_conflicted($content);
66 $tempdir = sys_get_temp_dir();
69 $ofile = tempnam($tempdir, "mtrack");
70 $nfile = tempnam($tempdir, "mtrack");
71 $tfile = tempnam($tempdir, "mtrack");
72 $pfile = tempnam($tempdir, "mtrack");
73 $diff3 = MTrackConfig::get('tools', 'diff3');
78 file_put_contents($ofile, $orig);
79 file_put_contents($nfile, $content);
80 file_put_contents($tfile, $doc->content);
82 if (PHP_OS == 'SunOS') {
83 exec("($diff3 -X $nfile $ofile $tfile ; echo '1,\$p') | ed - $nfile > $pfile",
84 $output = array(), $retval = 0);
86 exec("$diff3 -mX --label mine $nfile --label original $ofile --label theirs $tfile > $pfile",
87 $output = array(), $retval = 0);
91 /* see if there were merge conflicts */
93 $mine = preg_quote($nfile, '/');
94 $theirs = preg_quote($tfile, '/');
95 $orig = preg_quote($ofile, '/');
96 $content = file_get_contents($pfile);
98 if (PHP_OS == 'SunOS') {
99 $content = str_replace($nfile, 'mine', $content);
100 $content = str_replace($ofile, 'original', $content);
101 $content = str_replace($tfile, 'theirs', $content);
109 $conflicted = is_content_conflicted($content);
112 /* keep the merged version for editing purposes */
113 $_POST['content'] = $content;
114 /* our concept of the the original content is now what
115 * is currently saved */
116 $_POST['orig'] = base64_encode($doc->content);
119 $message = "Conflicting edits were detected; please correct them before saving";
121 $doc->content = $content;
123 $cs = MTrackChangeset::begin("wiki:$pi", $_POST['comment']);
125 if (is_array($_FILES['attachments'])) {
126 foreach ($_FILES['attachments']['name'] as $fileid => $name) {
128 switch ($_FILES['attachments']['error'][$fileid]) {
132 case UPLOAD_ERR_NO_FILE:
134 case UPLOAD_ERR_INI_SIZE:
135 case UPLOAD_ERR_FORM_SIZE:
136 $message = "Attachment(s) exceed the upload file size limit";
138 case UPLOAD_ERR_PARTIAL:
139 case UPLOAD_ERR_CANT_WRITE:
140 $message = "Attachment file upload failed";
142 case UPLOAD_ERR_NO_TMP_DIR:
143 $message = "Server configuration prevents upload due to missing temporary dir";
145 case UPLOAD_ERR_EXTENSION:
146 $message = "An extension prevented an upload from running";
148 if ($message !== null) {
149 throw new Exception($message);
152 MTrackAttachment::add("wiki:$pi",
153 $_FILES['attachments']['tmp_name'][$fileid],
154 $_FILES['attachments']['name'][$fileid],
159 MTrackAttachment::process_delete("wiki:$pi", $cs);
161 MTrackWikiItem::commitNow();
163 } catch (Exception $e) {
164 $message = $e->getMessage();
169 /* we're good; go back to view mode */
170 header("Location: ${ABSWEB}wiki.php/$pi");
177 /* now just render */
184 $ppi = htmlentities($pi, ENT_QUOTES, 'utf-8');
185 $editurl = $ABSWEB . "wiki.php/$pi";
189 if (!$edit && MTrackACL::hasAnyRights("wiki:$pi", 'modify')) {
190 $nav["$editurl?edit=1"] = 'Edit this Page';
194 $nav["/log.php/default/wiki/$doc->filename"] = "Page History";
197 $nav["/wiki.php?action=list"] = "Help & Title Index";
198 $nav["/wiki.php?action=recent"] = "Recent Changes";
200 if ($doc && $doc->file) {
201 $evt = $doc->file->getChangeEvent();
202 $reason = $evt->changelog;
203 if (!strlen($evt->changelog)) {
206 $reason = htmlentities($reason, ENT_QUOTES, 'utf-8');
207 echo "<div id='wikilastchange'>",
208 mtrack_username($evt->changeby, array('no_name' => true,
209 'class' => 'wikilastchange')),
211 mtrack_username($evt->changeby, array('no_image' => true)), " ",
212 mtrack_date($evt->ctime),
216 echo mtrack_nav("wikinav", $nav);
218 if (strlen($message)) {
219 echo "<br><div class='ui-state-error ui-corner-all'>" .
220 "<span class='ui-icon ui-icon-alert'></span>\n" .
221 htmlentities($message, ENT_QUOTES, 'utf-8') .
225 if (count($_GET) == 0 && ($doc === null || strlen($doc->content) == 0)) {
226 if (MTrackACL::hasAnyRights("wiki:$pi", 'create')) {
227 echo "Wiki page $ppi doesn't exist, would you like to create it?<br>";
230 <form name="launchwikiedit" method="GET" action="$editurl">
231 <input type="hidden" name="edit" value="1"/>
232 <button type="submit">Edit this page</button>
236 echo "Wiki page $ppi doesn't exist.<br>";
240 echo "<h1>Editing $ppi</h1>";
241 echo "<a href=\"{$ABSWEB}/help.php/WikiFormatting\" target=\"_blank\">Wiki Formatting</a> (opens in a new window)<br>\n";
243 $orig_content = isset($_POST['orig']) ? $_POST['orig']
244 : base64_encode($doc->content);
245 $content = isset($_POST['content']) ? $_POST['content'] : $doc->content;
246 $comment = isset($_POST['comment']) ? $_POST['comment'] : '';
247 $comment = htmlentities($comment, ENT_QUOTES, 'utf-8');
249 if (isset($_POST['preview'])) {
250 echo "<div class='wikipreview'>" .
251 MTrackWiki::format_to_html($content) . "</div>";
255 <form name="wikiedit" method="POST" action="$editurl" enctype='multipart/form-data'>
256 <input type="hidden" name="edit" value="1"/>
257 <input type="hidden" name="orig" value="$orig_content"/>
261 echo "<input type='hidden' name='conflicted' value='1'/>";
265 <textarea name="content" class="wiki"
266 rows="36" cols="78" style="width:100%;">$content</textarea>
268 <legend>Attachments</legend>
270 echo MTrackAttachment::renderDeleteList("wiki:$pi");
272 <label for='attachments[]'>Select file(s) to be attached</label>
273 <input type='file' class='multi' name='attachments[]'>
275 <fieldset id="changeinfo">
276 <legend>Change Information</legend>
277 <div class="field"><label>Comment about the change:<br/>
278 <input type="text" name="comment" size="60" value="$comment"/>
281 echo MTrackCaptcha::emit('wiki');
283 <div class="buttons">
284 <button type="submit" name="preview">Preview</button>
285 <button type="submit" name="save">Save changes</button>
286 <button type="submit" name="cancel">Cancel</button>
293 $action = isset($_GET['action']) ? $_GET['action'] : 'view';
297 echo MTrackWiki::format_to_html($doc->content);
298 echo MTrackAttachment::renderList("wiki:$pi");
299 if (MTrackACL::hasAnyRights("wiki:$doc->pagename", 'modify')) {
301 <form name="launchwikiedit" method="GET" action="$editurl">
302 <input type="hidden" name="edit" value="1"/>
303 <button type="submit">Edit this page</button>
310 echo "<h1>Help topics by Title</h1>\n";
313 function build_help_tree(&$tree, $dir) {
314 foreach (scandir($dir) as $ent) {
315 if ($ent[0] == '.') {
318 $full = $dir . DIRECTORY_SEPARATOR . $ent;
321 build_help_tree($kid, $full);
324 $tree[$ent] = array();
328 function emit_tree($root, $parent, $phppage)
332 if (strlen($parent)) {
335 echo "<ul class='wikitree'>\n";
337 $knames = array_keys($root);
338 usort($knames, 'strnatcasecmp');
339 foreach ($knames as $key) {
341 $n = htmlentities($key, ENT_QUOTES, 'utf-8');
345 emit_tree($kids, "$parent$key/", $phppage);
347 echo "<a href=\"${ABSWEB}$phppage/$parent$n\">$n</a>";
354 build_help_tree($htree, dirname(__FILE__) . '/../defaults/help');
355 emit_tree($htree, '', 'help.php');
357 echo "<h1>Wiki pages by Title</h1>\n";
358 /* get the page names into a tree format */
360 $root = MTrackWikiItem::getRepoAndRoot($repo);
361 $suf = MTrackConfig::get('core', 'wikifilenamesuffix');
363 function build_tree(&$tree, $repo, $dir, $suf) {
364 $items = $repo->readdir($dir);
365 foreach ($items as $file) {
366 $label = basename($file->name);
369 build_tree($kid, $repo, $file->name, $suf);
370 $tree[$label] = $kid;
372 if ($suf && substr($label, -strlen($suf)) == $suf) {
373 $label = substr($label, 0, strlen($label) - strlen($suf));
375 $tree[$label] = array();
380 build_tree($tree, $repo, $root, $suf);
382 emit_tree($tree, '', 'wiki.php');
385 <script type='text/javascript'>
386 $(document).ready(function(){
387 $('ul.wikitree').treeview({
399 <h1>Recently Edited Wiki Pages</h1>
400 <table class="history">
408 $root = MTrackWikiItem::getRepoAndRoot($repo);
409 foreach ($repo->history(null, 100) as $e) {
410 $d = mtrack_date($e->ctime);
411 list($page) = $e->files;
413 $page = substr($page, strlen($root)+1);
415 $author = mtrack_username($e->changeby);
416 $reason = htmlentities($e->changelog, ENT_QUOTES, 'utf-8');
418 echo "<tr><td><a href=\"${ABSWEB}wiki.php/$page\">$page</a></td><td>$d</td><td>$author</td><td>$reason</td></tr>\n";