Revision [16034]
This is an old revision of WikiFile made by ChewBakka on 2007-02-02 17:49:34.
For example, a category is a page to which other pages link. If you want to start a new category, you do not need to learn something new - just create the category page and link your pages to it.
Here I would like to present a solution where a file is represented by a page too. I will first give a description on how to use it, then the necessary pieces of code.
Description
On the server side, there are no file names any more - any file is "contained" in a particular page and referenced using only the page name. If the file is an image, it is visible in the page (through the { {file} } action) along with explaining text which is writen in the page as usual. The access rights for viewing and mpdifying files are just the page rights.
I order to add a screenshot (or any other file) to your wiki, you will first create a page for it. This is something youshould do anyway, because you should write some explaining text about your screenshot. The page should include a { {file} } action to your page, although this is not necessary for being a file page - it is just for file pages what the { {category} } action is for category pages.
The page footer reads Edit page :: File :: Stats :: Referrers and so on - note the addition of File. Clicking on it opens the file handler, which displays informations about the file (if there is already a file in the page) and an upload form; uploading a file into a page which already contains a file causes the old file to be replaced with the new file - there can be only one file per page.
From now on you can use your screenshot on othe wiki pages too. Just add { {file page="MyScreenShot"} } to the referring page.
And of cause all of this works with other file types too. If a file is not an image, then the same action displays an URL through which you can download the file.
Code
Below are five pieces of code. The files Wakka.class.php and footer.php are parts of the Wikka software; I have extended them without changing existing functions (hopefully). I have also added two files: actions/file.php and handlers/page/file.php. I did everything in Wikka 1.1.6.2 so I can not tell whether it will work in older versions.
Here comes the modification of actions/footer.php; lines 5,6,7 are added, anything else remains unchanged. This adds File:: to the footer.
- <div class="footer">
- <?php
- echo $this->FormOpen("", "TextSearch", "get");
- echo $this->HasAccess("write") ? "<a href=\"".$this->href("edit")."\" title=\"Click to edit this page\">Edit page</a> ::\n" : "";
- echo ($this->HasAccess("write") || $this->HasAccess("read"))
- ? '<a href="' . $this->href("file"). '" title="Click to view/edit the file in this page">File</a> ::' . "\n"
- : '';
- // ...
In Wakka.class.php I have extended the FormOpen function, because the html form must include an encoding attribute if you want to upload files. I have added a fourth parameter named $withFiles. This is the extended function:
- function FormOpen($method = "", $tag = "", $formMethod = "post", $withFile = false )
- {
- $enctype = '';
- if ($withFile) $enctype = ' enctype="multipart/form-data"';
- $result = "<form action=\"".$this->Href($method, $tag)."\" method=\"".$formMethod."\"$enctype>\n";
- if (!$this->config["rewrite_mode"]) $result .= "<input type=\"hidden\" name=\"wakka\" value=\"".$this->MiniHref($method, $tag)."\" />\n";
- return $result;
- }
Also in Wakka.class.php I have added four functions which perform the most basic file handling without access right checking. (One function is actually only a workaround for probllems with mime_content_type() which I experienced). I have just added them and the end of the class, and they look like this:
- /**
- * Return mime type for the given file extension.
- * Slow, but useful if PHP's mime_content_type() cannot be used.
- * Uses Wikka's mime_types.txt and some hardcoded associations.
- *
- * @author {@link http://wikkawiki.org/ChewBakka ChewBakka} (first draft)
- * @input $extension file extension, e.g. 'png', 'jpg', 'ogg'
- * @output mime content type, e.g. 'image/png', or empty string.
- */
- function MimeTypeFromExtension( $extension )
- {
- // Quick resonse for most frequently used file types
- if ($extension == 'png') return 'image/png';
- if ($extension == 'jpg') return 'image/jpeg';
- if ($extension == 'ogg') return 'application/ogg';
- // If not recoginzed, use mime_types.txt
- {
- {
- {
- {
- return $a[0];
- }
- }
- }
- }
- return ''; // if nothing was found
- }
- /**
- * Return an array describing the file which is stored in a page.
- *
- * @author {@link http://wikkawiki.org/ChewBakka ChewBakka} (first draft)
- * @input $tag name of the page; default = current page.
- * @output Array or (if no file in page) null. Keys:
- * extension file extension, e.g. 'png', 'jpg', 'ogg'
- * content-type mime content type, e.g. 'image/png'
- * uploaded when and who,. e.g. '2007-01-31 ChewBakka'
- * image 'yes' or 'no'
- * width Width in pixels (images only)
- * height Height in pixels (images only)
- * filename PageName.extension
- * path upload_path/PageName.extension
- * url 'http://..../PageName/file?action=get'
- */
- function GetFile( $tag = '' )
- {
- $data = null; // this variable will be returned
- if (!$tag) $tag = $this->tag;
- $metafile = $this->config['upload_path'].'/'.$tag.'.file'; // metadata
- {
- // Lines look like "key: value" -> convert into array
- 'extension' => '',
- 'content-type' => '',
- 'uploaded' => '',
- 'image' => 'false',
- 'width' => '',
- 'height' => '',
- 'filename' => '',
- 'path' => '',
- 'url' => ''
- );
- foreach ($lines as $line)
- {
- {
- }
- }
- // Convenient attributes which can not be stored permanently
- $data['filename'] = $tag . '.' . $data['extension'];
- $data['path'] = $this->config['upload_path'] .'/' . $data['filename'];
- $data['url'] = $this->config['base_url'] . $tag . '/file' .
- ($this->config['rewrite_mode']=='1' ? '?' : '&') .
- 'action=get';
- // Final check: file must exist.
- {
- $data = null;
- }
- }
- return $data;
- }
- /**
- * Remove the file from the current page.
- *
- * @author {@link http://wikkawiki.org/ChewBakka ChewBakka} (first draft)
- * @input none
- * @output none
- */
- function RemoveFile()
- {
- if ($data = $this->GetFile())
- {
- }
- }
- /**
- * Store an http-uploaded file in the current page.
- * Any previous file will be replaced with the new file.
- *
- * @author {@link http://wikkawiki.org/ChewBakka ChewBakka} (first draft)
- * @input $uploaded_file An item from PHP's $_FILES array (see there)
- * @output None
- */
- function SaveFile( $uploaded_file )
- {
- $this->RemoveFile();
- $pathname = $this->config['upload_path'] . '/' . $this->tag;
- $path = $pathname . '/' . $extension;
- {
- if( ! $contenttype )
- {
- $contenttype = $this->MimeTypeFromExtension( $extension );
- }
- // build an array with metadata
- 'extension' => $extension,
- 'content-type' => $contenttype,
- 'image' => 'false'
- );
- {
- $data['image'] = 'true';
- $data['width'] = $size[0];
- $data['height'] = $size[1];
- }
- // Create metadata file
- $contents = '';
- foreach ($data as $key => $value)
- {
- $contents .= ($key . ': ' . $value . "\n");
- }
- }
- }
The remaining two code pieces are two new files. Both are named file.php, but one is a handler and the other one is an action.
Here comes handlers/page/file.php:
- <?php
- /**
- * Display file info and a small upload form.
- *
- * @package Handlers
- * @name File
- *
- * @author {@link http://wikkawiki.org/ChewBakka ChewBakka} (first draft)
- *
- * @input ?action=get returns the file via http
- * uploading a file causes storage of the file "in the page",
- * overwriting any previous page file.
- *
- */
- $has_read_access = $this->HasAccess('read');
- $has_write_access = $this->HasAccess('write') && $has_read_access;
- switch (True)
- {
- case $_REQUEST['action'] == 'get':
- // ?action=get
- if ($this->HasAccess('read') && $data = $this->GetFile())
- {
- }
- // User uploaded a file
- if ($has_write_access)
- {
- $uploadedfile = $_FILES['file'];
- if ($uploadedfile['error'] > 0)
- {
- // redirect to page
- $this->redirect( $this->Href(), 'Transmitted file was damaged' );
- }
- else
- {
- $this->SaveFile( $uploadedfile );
- $this->Redirect( $this->Href() );
- }
- }
- default:
- // Display file info and an upload form
- $data = null;
- if ($has_read_access)
- {
- if ($data = $this->GetFile())
- {
- print '<h3>Existing file</h3><p>';
- foreach ($data as $key => $value)
- {
- if ($key != 'url')
- {
- }
- }
- $a = '< href="' . $data['url'] . '">' . $data['url'] . '</a>';
- print 'url: ' . $this->ReturnSafeHTML($a) . '<br />';
- print 'Wikka syntax: {{file page="' . $this->GetPageTag() . '"}}' . '<br />';
- print '</p>';
- }
- else
- {
- print '<p>There is no file yet</p>';
- }
- }
- else
- {
- print '<div class="page"><em>Sorry, you are nor allowed to view this file.</em></div>';
- }
- if ($has_write_access)
- {
- print '<h3>Upload form</h3><p>';
- print $this->FormOpen( 'file', $this->GetPageTag(), 'POST', true );
- print '<input name="file" type="file" size="72">';
- print '<input type="submit" value="upload">';
- print $this->FormClose();
- if ($data) print '<p>Note: the uploaded file will <em>replace</em> the existing file.</p>';
- }
- else
- {
- print '<div class="page"><em>Sorry, you are nor allowed to put a file here.</em></div>';
- }
- }
- ?>
And finally actions/file.php
- <?php
- /**
- * Display the page's file, either inline or as link.
- *
- * If the file is an image, then it is displayed inline.
- * For other file types, a download link is printed.
- * Note that at most one file can be stored in a page.
- *
- * Syntax:
- * {{file [page="SomeWikkaName"]}}
- *
- * @package Actions
- * @name File
- *
- * @author {@link http://wikkawiki.org/ChewBakka ChewBakka} (first draft)
- *
- * @input string $page: name of the page whose file is to be displayed.
- * optional; default is the current page itself.
- */
- $output = '';
- // Check whether current has read access and if there is a file.
- if ($this->HasAccess( 'read', $tag ) && $data = $this->GetFile($tag))
- {
- if ($data['image'] == 'true')
- {
- // Image file - create an <img> tag
- $output = '<img src="' . $data['url'] . '"' .
- ' width="' . $data['width'] . '"' .
- ' height="' . $data['height'] . '"' .
- ' alt="' . $tag . '">';
- }
- else
- {
- // Plain file - create a download link
- $output = '<a href="' . $data['url'] . '">' . $data['url'] . '</a>';
- }
- }
- print $this->ReturnSafeHTML($output);
- ?>
Credits
While developing the above code, I browsed through many Wikka sources in order to learn how to write a good extension, and how to document it. They were too many to remember, so I just want to say thanks to all the people who made Wikka.