Wikka : WikiFile

HomePage :: Categories :: Index :: Changes :: Comments :: Documentation :: Blog :: Login/Register
Most recent edit on 2008-08-15 17:02:58 by ChewBakka [New version]

Additions:
Example: assume you have a photograph of the Millennium Falcon in a file named IMG_1234.JPG on your computer. You want to put it in the wiki into the MillenniumFalcon page
After uploading, you see the image in the page. A click on the image displays another form, allowing you to replace the photo with another one or just to delete it.
Behind the scenes, an uploaded file is stored in the uploads directory along with a metadata file. In the example above, Wikka stores the second file as MillenniumFalcon~jawas1.jpg along with MillenniumFalcon~javas1.file which is a plain ascii file containing some metadata.
* Syntax: Unknown action "file"
* Save this PHP file in the actions subdirectory.
$url = $wikka->config['base_url'] . $tag . '/file';
if( $id )
append ?id=value or &id=value
$url = $url . (strpos($url,'?')?'&':'?') . 'id=' . $id;
$data['url'] = $url;
$language = 'DE' ; change to 'DE' for german messages
$editid = '!NONE!'; id of the image to which an upload/delete form is shown
Read the parameters from Unknown action "file"
if (is_array($vars) )
if( array_key_exists('page', $vars)) { $tag = $vars['page']; }
if( array_key_exists( 'id', $vars)) { $id = $vars[ 'id' ]; }
if( array_key_exists('editid', $_REQUEST))
$editid = $_REQUEST['editid'];
The user is allowed to edit (= replace or delete) the file,
if it is attached to the same page that the user is viewing,
and the user may edit the page.
$mayEdit = $this->HasAccess('write',$tag) && $tag
'DE'?'[BEARBEITEN]':'[EDIT]') . '</a>';
if ($mayEdit && ($id
$editid || $data
null))
If on the same page and requested, also show an upload/delete form
$hidelink = ;
switch($language)
case 'DE':
$headline = 'Eine Datei hochladen, so dass sie an dieser Stelle erscheint';
$buttonlabel = 'Hochladen';
if( $data )
$headline = ($data['image']
$deletelink = '<br />'
. ($data['image'] 'true' ? 'Obiges Bild' : 'Obige Datei' )
. ' aus dem Wiki '
. '<a href="' . $data['url'] . (strpos($data['url'],'?')?'&':'?')
. 'cmd=delete">L&Ouml;SCHEN</a>';
$hidelink = '<br />Dieses Formular <a href="' . $this->Href() . '">AUSBLENDEN</a>';
break;
default:
$headline = 'Upload a file to appear here';
$buttonlabel = 'Upload';
if( $data )
$headline = 'REPLACE the '
. ($data['image']
. ' above by uploading a new file';
$buttonlabel = 'Upload';
$deletelink = '<br /><a href="' . $data['url'] . (strpos($data['url'],'?')?'&':'?')
. 'cmd=delete">DELETE</a>'
. ' the '
. ($data['image'] 'true' ? 'image' : 'file' )
. ' above from the wiki';
$hidelink = '<br /><a href="' . $this->Href() . '">HIDE</a> this form';
. (!$this->config["rewrite_mode"] ? '<input type="hidden" name="wakka" value="' . $miniref . '" />' : )
. $hidelink
* Save this PHP file in the handlers/page subdirectory.
Save the data array in the metadata file
And now for the last step - read your wikka.config.php, it should contain a line like this:

Deletions:
Example: assume you have a photograph of the Millennium Falcon in a file named IMG_1234.JPG on your computer. You want to put it in the wiki.
After uploading, you see the image in the page, and below the image another upload form is visible, in case you want to replace the photo with another one later. You can also delete the file.
* Syntax: Unknown action "file"
$data['url'] = $wikka->config['base_url'] . $tag . '/file' . ($id?'?id='.$id:);
$uploadform = False; Show an upload form instead of the file?
if (is_array($vars) && array_key_exists('page', $vars))
$tag = $vars['page'];
if (is_array($vars) && array_key_exists('id', $vars))
$id = $vars['id'];
Check whether current user has read access and if there is a file.
$output = '<a href="' . $tag . '">'
. '<img src="' . $data['url'] . '"'
. ' alt="' . $tag . '"'
. ' border="0">'
. '</a>';
Plain file - create a download link
if ($this->HasAccess( 'write', $tag ) && $tag
$this->GetPageTag())
If on the same page, also show an upload form
$headline = 'Upload a file to appear here';
$buttonlabel = 'Upload';
if( $data )
$headline = 'REPLACE the '
. ($data['image']
'true' ? 'image' : 'file' )
. ' above by uploading a new file';
$buttonlabel = 'Upload';
$deletelink = '<br /><a href="' . $data['url'] . (strpos($data['url'],'?')?'&':'?')
. 'cmd=delete">DELETE</a>'
. ' the '
. ($data['image'] 2007-Feb-05
handlers/page/file.php: bugfix (switch without break, now if/elseif); sends filename with download (makes download easier)
libs/Wakka.class.php: supports *.*.gz
2008-Jul-15
Complete rewrite.
Only ACTION and HANDLER; no more Wikka.class.php modifications.
2008-Jul-18
Multiple files per page now possible.



Edited on 2008-07-18 14:13:36 by ChewBakka [Fixed another headline]

Additions:

How to install it



Deletions:

How to install it





Edited on 2008-07-18 14:08:26 by ChewBakka [Updated introduction; fixed headlines]

Additions:
This module allows you to put images (and other files) anywhere on any page (provided you have write access to that page).

How to use it

How it works

History

Credits



Deletions:
This pair of files allows you to attach files to wikipages.

How to use it

How it works

History

Credits





Edited on 2008-07-18 05:18:16 by ChewBakka

Additions:
To display an image also on another page, you do not need to upload it twice. Instead, you can tell the file placeholder to fetch the image from a different page: {{file page="PageWhichContainsTheFile"}}
2008-Jul-18
Multiple files per page now possible.


Deletions:
To display an image also on another page, you do not need to upload it twice. Instead, you can tell the file placeholder to fetch the image from a different place:
Unknown action "file"




Edited on 2008-07-18 05:16:42 by ChewBakka [Added advanced usage section]

Additions:
So you edit the respective page and put the {{file}} placeholder at the place where you want to see the image.

Advanced usage

To display an image also on another page, you do not need to upload it twice. Instead, you can tell the file placeholder to fetch the image from a different place:
Unknown action "file"


Deletions:
So you edit the repective page and put the {{file}} placeholder at the place where you want to see the image.



Edited on 2008-07-18 05:10:04 by ChewBakka [Multiple files]

Additions:
This pair of files allows you to attach files to wikipages.
So you edit the repective page and put the {{file}} placeholder at the place where you want to see the image.
===== Millennium Falcon  =====
Below you see a photograph of the Millennium Falcon, last year on Tatooine.
After uploading, you see the image in the page, and below the image another upload form is visible, in case you want to replace the photo with another one later. You can also delete the file.
Now, suppose you want to add more images to the same page. Then you need to distinguish the files by adding an **id**.
(text;;MillenniumFalcon)

Millennium Falcon

Below you see a photograph of the Millennium Falcon, last year on Tatooine.
On the next images, some Jawas admire the mighty space vessel:
Unknown action "file"
Unknown action "file"
As you see above, it is allowed to have one file per page which has no id. Also, don't worry about id of images on other pages - the id just need to be unique inside the wiki page.
* Displays a file in the page (as image or link) and optinally an upload form.
* Syntax: Unknown action "file"
* Reads the file's metadata file and returns it as an array.
* @output Array or (if no file in page) null.
function getFile( $tag, $wikka, $id )
$sep = ($id ? '~' : ); Separator between tag and id in filename
Read the metadata from the file TagName~id.file
$metafile = $wikka->config['upload_path'].'/'.$tag.$sep.$id.'.file';
Lines look like "key: value" -> convert them to an array
'extension' => , file extension, e.g. 'png', 'jpg', 'ogg'
'content-type' => , mime content type, e.g. 'image/png'
'uploaded' => '?', date and time, . e.g. '2007-01-31 18:00'
'uploader' => '?', wikiname, e.g. 'ChewBakka'
'image' => 'false', 'true' for image files
'width' => , width in pixels (images only)
'height' => height in pixels (images only)
Add convenient attributes which can not be stored permanently
$data['filename'] = $tag.$sep.$id . '.' . $data['extension'];
$data['path'] = $wikka->config['upload_path'] .'/' . $data['filename'];
$data['metafile'] = $metafile;
$data['url'] = $wikka->config['base_url'] . $tag . '/file' . ($id?'?id='.$id:);
$id = ; Optional file id, appended to the tag name
if (is_array($vars) && array_key_exists('id', $vars))
$id = $vars['id'];
if( $id )
A file ID was submitted.
Check if it is alphanumeric and not longer than 100 characters
in order to prevent security issues.
if (ereg('[^a-zA-Z0-9_]',$id) || strlen($id) > 100)
$id = '!BAD!';
$output = 'An illegal file ID was submittet';
if( $id != '!BAD!' )
$data = getFile($tag,$this,$id);
Check whether current user has read access and if there is a file.
if ($this->HasAccess( 'read', $tag ) && $data )
if ($data['image']
if ($this->HasAccess( 'write', $tag ) && $tag $this->GetPageTag())
If on the same page, also show an upload form
$headline = 'Upload a file to appear here';
$buttonlabel = 'Upload';
$deletelink = ;
if( $data )
$headline = 'REPLACE the '
. ($data['image']
. ' above by uploading a new file';
$buttonlabel = 'Upload';
$deletelink = '<br /><a href="' . $data['url'] . (strpos($data['url'],'?')?'&':'?')
. 'cmd=delete">DELETE</a>'
. ' the '
. ($data['image'] 'true' ? 'image' : 'file' )
. ' above from the wiki';
$miniref = $this->Href('file', $tag);
$output = $output
. '<br />' . $headline . ' <br />'
. '<form action="' . $miniref . '" method="POST" enctype="multipart/form-data">'
. (!$this->config["rewrite_mode"] ? '<input type="hidden" name="wakka" value="' . $miniref . '" />' : )
. '<input name="file" type="file" size="72">'
. '<input type="hidden" name="id" value="' . $id . '">'
. '<input type="submit" value="' . $buttonlabel . '">'
. $deletelink
. '</form><br />'
;
* Supports file retrieval and upload.
* Syntax: http://server/WikiName/file[?id=someid]
* Reads the file's metadata file and returns it as an array.
* @output Array or (if no file) null.
function getFile( $tag, $wikka, $id )
$sep = ($id ? '~' :
);
Separator between tag and id in filename
Read the metadata from the file TagName~id.file
$metafile = $wikka->config['upload_path'].'/'.$tag.$sep.$id.'.file';
Lines look like "key: value" -> convert them to an array
'extension' => , file extension, e.g. 'png', 'jpg', 'ogg'
'content-type' => , mime content type, e.g. 'image/png'
'uploaded' => '?', date and time, . e.g. '2007-01-31 18:00'
'uploader' => '?', wikiname, e.g. 'ChewBakka'
'image' => 'false', 'true' for image files
'width' => , width in pixels (images only)
'height' => height in pixels (images only)
Add convenient attributes which can not be stored permanently
$data['filename'] = $tag.$sep.$id . '.' . $data['extension'];
$data['path'] = $wikka->config['upload_path'] .'/' . $data['filename'];
$data['metafile'] = $metafile;
$data['url'] = $wikka->config['base_url'] . $tag . '/file' . ($id?'?id='.$id:);
* Store an http-uploaded file.
function saveFile( $uploaded_file, $wikka, $id )
$pathname = $wikka->config['upload_path'] . '/' . $wikka->tag . ($id?'~':
) . $id;
$contenttype = ;
Remove existing file if it already exists
if ($data = getFile( $wikka->GetPageTag(), $wikka, $id ) )
File exists; remove it first
E.g. if a GIF exists and the user replaces it with a PNG now.
unlink( $data['path'] );
unlink( $data['metafile'] );
$data = null;
Find the mime type (it will be stored in the metadata)
switch( $extension )
Quick resonse for most frequently used file types
case 'png':
$contenttype = 'image/png';
break;
case 'jpg':
$contenttype = 'image/jpeg';
break;
case 'ogg':
$contenttype = 'application/ogg';
break;
case 'zip':
$contenttype = 'application/zip';
break;
default:
Use wikka's own mime_types.txt
if (file_exists( $wikka->config['mime_types'] ))
{
foreach (explode("\n",file_get_contents($wikka->config['mime_types'])) as $line)
{
$line = trim($line);
if ($line != && substr($line,0,1) != '#' && strpos($line,$extension))
{
$a = explode( ' ', str_replace(chr(9),' ',$line) );
if (in_array( $extension, $a ))
{
$contenttype = $a[0];
break;
}
}
}
}
'uploaded' => date('Y-m-d H:i'),
'uploader' => $wikka->GetUserName(),
Save the dat aarry in the metadata file
$cmd = (isset($_REQUEST['cmd']) ? $_REQUEST['cmd'] : 'get');
if ($id = (isset($_REQUEST['id']) ? $_REQUEST['id'] : ))
A file ID was submitted.
Check if it is alphanumeric and not longer than 100 characters
in order to prevent security issues.
if (ereg('[^a-zA-Z0-9_]',$id) || strlen($id) > 100)
$cmd = 'nothing';
$cmd = 'upload';
switch( $cmd )
case 'upload':
User uploaded a file
if ($this->HasAccess('write'))
$uploadedfile = $_FILES['file'];
if ($uploadedfile['error'] > 0)
redirect to page
$this->redirect( $this->Href(), 'Transmitted file was damaged' );
else
saveFile( $uploadedfile, $this, $id );
$this->Redirect( $this->Href() );
$handled = True;
break;
case 'get':
Return the file
if ($this->HasAccess('read') && $data = getFile($this->GetPageTag(),$this,$id))
header( 'Content-Type: ' . $data['content-type'] );
if ($data['image'] != 'true')
header( 'Content-Disposition: attachment; filename="' . $data['filename'] . '"');
@readfile($data['path']);
exit();
$handled = True;
break;
case 'delete':
Delete the file permanently from the wiki
if ($this->HasAccess('write') && $data = getFile($this->GetPageTag(),$this,$id))
unlink( $data['metafile'] );
unlink( $data['path'] );
$this->Redirect( $this->Href() );
break;
$this->Redirect( $this->Href() );


Deletions:
In Wikka, almost everything is a page.
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.
You can also think of files as attachments; any wikka page can have at most one attachment.
First you create a page for the image, say MillenniumFalconOnTatooine, as follows, and save it.
===== Millennium Falcon photograph =====
Photograph of the Millennium Falcon, last year on Tatooine.
After uploading, you see the image in the page, and below the image another upload form is visible, in case you want to replace the photo with another one later.
In order to display the image on other pages, include the following modified file action in the other page:
(text;;Code for embedding an image from another page)
Unknown action "file"
This will display the image on another page.
And of cause all of this works with other file types too. If a file is not an image, then the file action displays an URL through which you can download the file.
* 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:
* Unknown action "file"
* @input string $page: name of the page whose file is to be displayed.
* optional; default is the current page itself.
* Return an array describing the file which is stored in a 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.ext
* path upload_path/PageName.extension
* url 'http://..../PageName/file'
function getFile( $tag, $wikka )
$metafile = $wikka->config['upload_path'].'/'.$tag.'.file'; metadata
Lines look like "key: value" -> convert into array
'extension' => ,
'content-type' => ,
'uploaded' => '<unknown> <unknown>',
'image' => 'false',
'width' => ,
'height' => ,
'filename' => ,
'path' => ,
'url' =>
Convenient attributes which can not be stored permanently
$data['filename'] = $tag . '.' . $data['extension'];
$data['path'] = $wikka->config['upload_path'] .'/' . $data['filename'];
$data['url'] = $wikka->config['base_url'] . $tag . '/file';
$data = getFile($tag,$this);
Check whether current user has read access and if there is a file.
if ($this->HasAccess( 'read', $tag ) && $data )
if ($data['image'] $this->GetPageTag()) If on the same page, also show an upload form
$headline = 'Attach a file to this page';
$buttonlabel = 'Attach selected file';
if( $data )
$headline = 'Replace above file/image with another one'
. '<br />'
. '(Note: if you do this, the new file/image will appear '
. 'INSTEAD of the existing file/image everywhere in the wiki!)'
;
$buttonlabel = 'REPLACE FILE/IMAGE (THINK TWICE!!!)';
$miniref = $this->Href('file', $tag);
$output = $output
. '<br />' . $headline . ' <br />'
. '<form action="' . $miniref . '" method="POST" enctype="multipart/form-data">'
. (!$this->config["rewrite_mode"] ? '<input type="hidden" name="wakka" value="' . $miniref . '" />' : )
. '<input name="file" type="file" size="72">'
. '<input type="submit" value="' . $buttonlabel . '">'
. '</form><br />'
;
* @input ?action=get returns the file via http
* uploading a file causes storage of the file "in the page",
* overwriting any previous page file.
* mimeTypeFromExtension()
* 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.
* @input $extension file extension, e.g. 'png', 'jpg', 'ogg'
* @output mime content type, e.g. 'image/png', or empty string.
function mimeTypeFromExtension( $extension, $wikka )
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
if (file_exists( $wikka->config['mime_types'] ))
foreach (explode("\n",file_get_contents($wikka->config['mime_types'])) as $line)
$line = trim($line);
if ($line != && substr($line,0,1) != '#' && strpos($line,$extension))
$a = explode( ' ', str_replace(chr(9),' ',$line) );
if (in_array( $extension, $a ))
return $a[0];
return ;
if nothing was found
* saveFile()
* Store an http-uploaded file in the current page.
* Any previous file will be replaced with the new file.
function saveFile( $uploaded_file, $wikka )
$pathname = $wikka->config['upload_path'] . '/' . $wikka->tag;
$contenttyp = ;
$contenttype = mimeTypeFromExtension( $extension );
'uploaded' => date('Y-m-d H:i') . ' ' . $wikka->GetUserName(),
Create metadata file
* Return an array describing the file which is stored in a 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.ext
* path upload_path/PageName.extension
* url 'http://..../PageName/file'
function getFile( $tag, $wikka )
$metafile = $wikka->config['upload_path'].'/'.$tag.'.file';
metadata
Lines look like "key: value" -> convert into array
'extension' => ,
'content-type' => ,
'uploaded' => '<unknown> <unknown>',
'image' => 'false',
'width' => ,
'height' => ,
'filename' => ,
'path' => ,
'url' =>
Convenient attributes which can not be stored permanently
$data['filename'] = $tag . '.' . $data['extension'];
$data['path'] = $wikka->config['upload_path'] .'/' . $data['filename'];
$data['url'] = $wikka->config['base_url'] . $tag . '/file';
User uploaded a file
if ($this->HasAccess('write'))
$uploadedfile = $_FILES['file'];
if ($uploadedfile['error'] > 0)
redirect to page
$this->redirect( $this->Href(), 'Transmitted file was damaged' );
saveFile( $uploadedfile, $this );
$this->Redirect( $this->Href() );
else
No upload => return the file
if ($this->HasAccess('read') && $data = getFile($this->GetPageTag(),$this))
header( 'Content-Type: ' . $data['content-type'] );
if ($data['image'] != 'true')
header( 'Content-Disposition: attachment; filename="' . $data['filename'] . '"');
@readfile($data['path']);
exit();
$this->Redirect( $this->Href(), 'Unknown' );




Edited on 2008-07-16 01:50:39 by ChewBakka [some german-language strings replaced with english ones]

Additions:
$headline = 'Attach a file to this page';
$buttonlabel = 'Attach selected file';
$headline = 'Replace above file/image with another one'
. '(Note: if you do this, the new file/image will appear '
. 'INSTEAD of the existing file/image everywhere in the wiki!)'
$buttonlabel = 'REPLACE FILE/IMAGE (THINK TWICE!!!)';


Deletions:
$headline = 'An diesen Artikel eine Datei anhängen'; $buttonlabel = 'Daten anhängen';
$headline = 'Obige Datei durch eine andere überschreiben'
. '(Wenn Sie das tun, dann erscheint anstelle der '
. 'obigen Datei die neue Datei!)'
$buttonlabel = 'Datei &Uuml;BERSCHREIBEN (VORSICHT!!!)';




Edited on 2008-07-15 10:05:24 by ChewBakka [Fixed a bug in the action which occured in pages with multiple images]

Additions:
if( !function_exists('getFile') ) for pages which include multiple files function getFile( $tag, $wikka )
$data = null; this variable will be returned
$metafile = $wikka->config['upload_path'].'/'.$tag.'.file'; metadata
if (file_exists($metafile) && $contents = file_get_contents($metafile))
$lines = explode( "\n", $contents );
Lines look like "key: value" -> convert into array
$data = array(
'extension' => ,
'content-type' => ,
'uploaded' => '<unknown> <unknown>',
'image' => 'false',
'width' => ,
'height' => ,
'filename' => ,
'path' => ,
'url' =>
);
foreach ($lines as $line)
$a = explode( ':', trim($line), 2 );
if( count($a)
2 )
$data[ $a[0] ] = trim( $a[1] );
Convenient attributes which can not be stored permanently
$data['filename'] = $tag . '.' . $data['extension'];
$data['path'] = $wikka->config['upload_path'] .'/' . $data['filename'];
$data['url'] = $wikka->config['base_url'] . $tag . '/file';
Final check: file must exist.
if (! file_exists( $data['path'] ) )
$data = null;
return $data;

$headline = 'An diesen Artikel eine Datei anhängen';
$buttonlabel = 'Daten anhängen';
$headline = 'Obige Datei durch eine andere überschreiben'
. '<br />'
. '(Wenn Sie das tun, dann erscheint anstelle der '
. 'obigen Datei die neue Datei!)'
;
$buttonlabel = 'Datei &Uuml;BERSCHREIBEN (VORSICHT!!!)';


Deletions:
function formOpen( $wikka, $method = , $tag = , $formMethod = "post", $withFile = false ) $enctype = ;
if ($withFile) $enctype = ' enctype="multipart/form-data"';
$result = "<form action=\.$wikka->Href($method, $tag)."\" method=\.$formMethod."\"$enctype>\n";
if (!$wikka->config["rewrite_mode"]) $result .= "<input type=\"hidden\" name=\"wakka\" value=\"".$wikka->MiniHref($method, $tag)."\" />\n";
return $result;
$headline = 'Attach one file to this article';
$buttonlabel = 'attach file';
$headline = 'REPLACE THIS ATTACHMENT WITH A DIFFENT FILE';
$buttonlabel = 'REPLACE (THINK TWICE!!!)';




Edited on 2008-07-15 08:36:35 by ChewBakka [Rewrote the code and the documentation]

Additions:

WikiFile action and handler

You can also think of files as attachments; any wikka page can have at most one attachment.
Example: assume you have a photograph of the Millennium Falcon in a file named IMG_1234.JPG on your computer. You want to put it in the wiki.
First you create a page for the image, say MillenniumFalconOnTatooine, as follows, and save it.
===== Millennium Falcon photograph =====
Photograph of the Millennium Falcon, last year on Tatooine.
There was lots of sand, as always.
{{file}}
The page now shows a form which allows you to upload the file.
After uploading, you see the image in the page, and below the image another upload form is visible, in case you want to replace the photo with another one later.
In order to display the image on other pages, include the following modified file action in the other page:
(text;;Code for embedding an image from another page)
Unknown action "file"
This will display the image on another page.
And of cause all of this works with other file types too. If a file is not an image, then the file action displays an URL through which you can download the file.
We are going to add two program files to the Wikka software, and create a folder.
In your Wikka root directory, there is a folder named actions which contains several php files. Save the following code (use the grab button) as file.php in the actions folder.
 * WikiFile action
 * {{file [page="SomeWikkaName"]}}
 * Return an array describing the file which is stored in a page.
 * @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.ext
 *          path          upload_path/PageName.extension
 *          url           'http://..../PageName/file'
function getFile( $tag, $wikka )
   $data = null; // this variable will be returned
   $metafile = $wikka->config['upload_path'].'/'.$tag.'.file';  // metadata
   if (file_exists($metafile) && $contents = file_get_contents($metafile))
	  {
	  $lines = explode( "\n", $contents );
	  // Lines look like "key: value" -> convert into array
	  $data = array(
		 'extension'    => '',
		 'content-type' => '',
		 'uploaded'     => '<unknown>        <unknown>',
		 'image'        => 'false',
		 'width'        => '',
		 'height'       => '',
		 'filename'     => '',
		 'path'         => '',
		 'url'          => ''
	  );
	  foreach ($lines as $line)
	  {
		 $a = explode( ':', trim($line), 2 );
		 if( count($a) == 2 )
		 {
			$data[ $a[0] ] = trim( $a[1] );
		 }
	  }
	  // Convenient attributes which can not be stored permanently
	  $data['filename'] = $tag . '.' . $data['extension'];
	  $data['path'] = $wikka->config['upload_path'] .'/' . $data['filename'];
	  $data['url'] = $wikka->config['base_url'] . $tag .  '/file';
	  // Final check: file must exist.
	  if (! file_exists( $data['path'] ) )
	  {
		 $data = null;
	  }
   }
   return $data;
function formOpen( $wikka, $method = "", $tag = "", $formMethod = "post", $withFile = false )
   $enctype = '';
   if ($withFile) $enctype = ' enctype="multipart/form-data"';
   $result = "<form action=\"".$wikka->Href($method, $tag)."\" method=\"".$formMethod."\"$enctype>\n";
   if (!$wikka->config["rewrite_mode"]) $result .= "<input type=\"hidden\" name=\"wakka\" value=\"".$wikka->MiniHref($method, $tag)."\" />\n";
   return $result;
 * Here the real action starts
// Initialize variables
$output = ''; // The HTML code that is being generated by this action
$uploadform = False; // Show an upload form instead of the file?
$tag = $this->GetPageTag(); // The page that the user requested
if (is_array($vars) && array_key_exists('page', $vars))
   $tag = $vars['page'];
$data = getFile($tag,$this);
// Check whether current user has read access and if there is a file.
if ($this->HasAccess( 'read', $tag ) && $data )
   if ($data['image'] == 'true')
   {
	  // Image file - create an <img> tag
	  $output =  '<a href="'  . $tag . '">'
			  .  '<img src="' . $data['url']    . '"'
			  .  ' width="'   . $data['width']  . '"'
			  .  ' height="'  . $data['height'] . '"'
			  .  ' alt="'     . $tag            . '"'
			  .  ' border="0">'
			  .  '</a>';
   }
   else
   {
	  // Plain file - create a download link
	  $output = '<a href="' . $data['url'] . '">' . $data['url'] . '</a>';
   }
if ($this->HasAccess( 'write', $tag ) && $tag == $this->GetPageTag())
   // If on the same page, also show an upload form
   $headline = 'Attach one file to this article';
   $buttonlabel = 'attach file';
   if( $data )
   {
	  $headline    = 'REPLACE THIS ATTACHMENT WITH A DIFFENT FILE';
	  $buttonlabel = 'REPLACE (THINK TWICE!!!)';
   }
   $miniref = $this->Href('file', $tag);
   $output = $output
		   . '<br />' . $headline . ' <br />'
	  	  . '<form action="' . $miniref . '" method="POST" enctype="multipart/form-data">'
				. (!$this->config["rewrite_mode"] ? '<input type="hidden" name="wakka" value="' . $miniref . '" />' : '')
		   . '<input name="file" type="file" size="72">'
		   . '<input type="submit" value="' . $buttonlabel . '">'
		   . '</form><br />'
		   ;
(php;1;handlers/page/file.php)
* WikiFile handler
* mimeTypeFromExtension()
* 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.
* @input $extension file extension, e.g. 'png', 'jpg', 'ogg'
* @output mime content type, e.g. 'image/png', or empty string.
function mimeTypeFromExtension( $extension, $wikka )
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
if (file_exists( $wikka->config['mime_types'] ))
{
foreach (explode("\n",file_get_contents($wikka->config['mime_types'])) as $line)
{
$line = trim($line);
if ($line != && substr($line,0,1) != '#' && strpos($line,$extension))
{
$a = explode( ' ', str_replace(chr(9),' ',$line) );
if (in_array( $extension, $a ))
return $a[0];
}
}
}
return ; if nothing was found
* saveFile()
* Store an http-uploaded file in the current page.
* Any previous file will be replaced with the new file.
* @input $uploaded_file An item from PHP's $_FILES array (see there)
* @output None
function saveFile( $uploaded_file, $wikka )
$pathinfo = pathinfo( $uploaded_file['name'] );
$extension = strtolower( $pathinfo['extension'] );
$pathname = $wikka->config['upload_path'] . '/' . $wikka->tag;
$path = $pathname . '.' . $extension;
$contenttyp = ;
if (move_uploaded_file( $uploaded_file['tmp_name'], $path ))
{
if( function_exists('mime_content_type') )
{
$contenttype = mime_content_type($path);
}
if( ! $contenttype )
{
$contenttype = mimeTypeFromExtension( $extension );
}
build an array with metadata
$data = array(
'extension' => $extension,
'content-type' => $contenttype,
'uploaded' => date('Y-m-d H:i') . ' ' . $wikka->GetUserName(),
'image' => 'false'
);
if( substr($data['content-type'],0,6)
'image/' )
{
$data['image'] = 'true';
$size = getimagesize($path);
$data['width'] = $size[0];
$data['height'] = $size[1];
}
Create metadata file
$contents = ;
foreach ($data as $key => $value)
{
$contents .= ($key . ': ' . $value . "\n");
}
file_put_contents( $pathname . '.file', $contents );
}
* Return an array describing the file which is stored in a page.
* @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.ext
* path upload_path/PageName.extension
* url 'http://..../PageName/file'
function getFile( $tag, $wikka )
$data = null;
this variable will be returned
$metafile = $wikka->config['upload_path'].'/'.$tag.'.file'; metadata
if (file_exists($metafile) && $contents = file_get_contents($metafile))
{
$lines = explode( "\n", $contents );
Lines look like "key: value" -> convert into array
$data = array(
'extension' => ,
'content-type' => ,
'uploaded' => '<unknown> <unknown>',
'image' => 'false',
'width' => ,
'height' => ,
'filename' => ,
'path' => ,
'url' =>
);
foreach ($lines as $line)
{
$a = explode( ':', trim($line), 2 );
if( count($a)
2 )
{
$data[ $a[0] ] = trim( $a[1] );
}
}
Convenient attributes which can not be stored permanently
$data['filename'] = $tag . '.' . $data['extension'];
$data['path'] = $wikka->config['upload_path'] .'/' . $data['filename'];
$data['url'] = $wikka->config['base_url'] . $tag . '/file';
Final check: file must exist.
if (! file_exists( $data['path'] ) )
{
$data = null;
}
}
return $data;
* Here the real handler starts
$handled = False;
if (isset($_FILES['file']))
User uploaded a file
if ($this->HasAccess('write'))
{
$uploadedfile = $_FILES['file'];
if ($uploadedfile['error'] > 0)
{
redirect to page
$this->redirect( $this->Href(), 'Transmitted file was damaged' );
}
else
{
saveFile( $uploadedfile, $this );
$this->Redirect( $this->Href() );
}
$handled = True;
}
No upload => return the file
if ($this->HasAccess('read') && $data = getFile($this->GetPageTag(),$this))
{
header( 'Content-Type: ' . $data['content-type'] );
if ($data['image'] != 'true')
{
header( 'Content-Disposition: attachment; filename="' . $data['filename'] . '"');
}
@readfile($data['path']);
exit();
$handled = True;
}
if( !$handled )
$this->Redirect( $this->Href(), 'Unknown' );
%%(php;40;wikka.config.php)
This means that the Wikka root folder should contain a folder named
uploads; please create this folder if it does not exist.
Should the above line not be in your config file, please add the line too.
2008-Jul-15
Complete rewrite.
Only ACTION and HANDLER; no more Wikka.class.php modifications.
Category: User contributions


Deletions:

WikiFile action

Once installed in your Wikka wiki, users will find it very easy to put files in the wiki.
There are no folders and file names - 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 along with explaining text which is writen in the page as usual, and can be embedded in other pages by just referencing the file's page name. The access rights for viewing and modifying files are just the page rights.
Example: assume you have a photograph of the Millennium Falcon in a file named IMG_1234.JPG on your computer. You want to put it in the wiki and embed it in a general page about the Millennium Falcon. First you create another page for the image itself, say MillenniumFalconOnTatooine, and type
  • Photograph of the Millennium Falcon, last year on Tatooine.
  • {{file}}
into it, and save it.
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;
Note that 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.
Now you can include it in the MillenniumFalcon page and any other page. Just write {{file page="MillenniumFalconOnTatooine"}} into it, and it shows up in the 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.
We are going to add two program files to the Wikka software, modify two others, and create a folder.
Let us begin with the most easy step. In your Wikka root directory, there is a folder named actions which contains several php files. Save the following code (use the grab button) as file.php in the actions folder.
  1. *    {{file [page="SomeWikkaName"]}}
  2. $tag = (is_array($vars) && array_key_exists('page',$vars)) ? $vars['page'] : $this->GetPageTag();
  3. $output = '';
  4. // Check whether current has read access and if there is a file.
  5. if ($this->HasAccess( 'read', $tag ) && $data = $this->GetFile($tag))
  6.     if ($data['image'] == 'true')
  7.     {
  8.         // Image file - create an <img> tag
  9.         $output = '<img src="'    . $data['url']    . '"' .
  10.                       ' width="'  . $data['width']  . '"' .
  11.                       ' height="' . $data['height'] . '"' .
  12.                       ' alt="'    . $tag            . '">';
  13.     }
  14.     else
  15.     {
  16.         // Plain file - create a download link
  17.         $output = '<a href="' . $data['url'] . '">' . $data['url'] . '</a>';
  18.     }
(php;1)
* Display file info and a small upload form.
$has_read_access = $this->HasAccess('read');
$has_write_access = $this->HasAccess('write') && $has_read_access;
if ($_REQUEST['action']
'get')
?action=get
if ($this->HasAccess('read') && $data = $this->GetFile())
{
header( 'Content-Type: ' . $data['content-type'] );
if ($data['image'] != 'true')
{
header( 'Content-Disposition: attachment; filename="' . $data['filename'] . '"');
}
@readfile($data['path']);
exit();
}
elseif (isset($_FILES['file']))
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() );
}
}
Display file info and an upload form
if ($has_read_access)
{
$upload_form = ( $has_write_access ?
$this->FormOpen( 'file', $this->GetPageTag(), 'POST', true ) .
'<input name="file" type="file" size="72">' .
'<input type="submit" value="upload">' .
$this->FormClose() . ' <br />'
: );
if ($data = $this->GetFile())
{
Page contains a file
print '<p>';
print 'This page contains a ' . $data['extension'] . ' file.';
if ($data['image']
'true')
print ' This is an image, ';
print $data['width'] . ' pixels wide and ';
print $data['height'] . ' pixels high.';
$a = '<a href="' . $data['url'] . '">' . $data['url'] . '</a>';
print ' ' . substr($data['uploaded'],17) . ' has uploaded it on '; user
print substr($data['uploaded'],0,16) . '.<br />'; date and time
print 'It can be downloaded using the URL ' . $this->ReturnSafeHTML($a) . '.<br />';
print 'However, for using it in a Wikka page just place the following code in the page:<br />';
print 'Unknown action "file"<br />';
print '</p>';
if( $has_write_access )
print '<p>You can <em>replace</em> it with another file using this form:</p>';
print $upload_form;
}
else
{
Page does not contain a file
print '<p>There is no file in this page.</p>';
if( $has_write_access )
print '<p>You can store one file in this page using this form:</p>';
print $upload_form;
}
}
else
{
no read access to page => no access to file
print '<div class="page"><em>Sorry, you are nor allowed to view this page.</em></div>';
}
Next, we will modify two existing Wikka program files. Be sure to keep backup copies of them!
Ok, return to the
actions folder and open the footer.php file in your favorite text editor. Add three lines as described in the code box; this adds File:: to the footer.
  1. <div class="footer">
  2. <?php
  3.     echo $this->FormOpen("", "TextSearch", "get");
  4.     echo $this->HasAccess("write") ? "<a href=\"".$this->href("edit")."\" title=\"Click to edit this page\">Edit page</a> ::\n" : "";
  5.     // footer.php should begin with the above lines.
  6.     // Insert the following three lines here:
  7.     echo ($this->HasAccess("write") || $this->HasAccess("read"))
  8.         ? '<a href="' . $this->href("file"). '" title="Click to view/edit the file in this page">File</a> ::' . "\n"
  9.         : '';
  10.     // The rest of footer.php remains unchanged below
  11. In the //libs// folder there is a huge file named //Wakka.class.php//. Open it and find the lines that start with function ""FormOpen"" (line no. 692) and end with a closing }. (Be careful since the next function, ""FormClose"", comes right after ""FormOpen""). Replace the ""FormOpen"" function with this extended version (it supports the //encoding// attribute which is necessary for file uploads):
  12.  
(php;692)
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;
}
And finally, insert the following four functions at the end of the
Wakka.class.php (but before the final closing } brace):
  1.     /**
  2.     * Return mime type for the given file extension.
  3.     * Slow, but useful if PHP's mime_content_type() cannot be used.
  4.     * Uses Wikka's mime_types.txt and some hardcoded associations.
  5.     *
  6.     * @author  {@link http://wikkawiki.org/ChewBakka ChewBakka} (first draft)
  7.     * @input   $extension file extension, e.g. 'png', 'jpg', 'ogg'
  8.     * @output  mime content type, e.g. 'image/png', or empty string.
  9.     */
  10.     function MimeTypeFromExtension( $extension )
  11.     {
  12.         // Quick resonse for most frequently used file types
  13.         if ($extension == 'png') return 'image/png';
  14.         if ($extension == 'jpg') return 'image/jpeg';
  15.         if ($extension == 'ogg') return 'application/ogg';
  16.         // If not recoginzed, use mime_types.txt
  17.         if (file_exists( $this->config['mime_types'] ))
  18.         {
  19.             foreach (explode("\n",file_get_contents($this->config['mime_types'])) as $line)
  20.                 $line = trim($line);
  21.                 if ($line != '' && substr($line,0,1) != '#' && strpos($line,$extension))
  22.                 {
  23.                     $a = explode( ' ', str_replace(chr(9),' ',$line) );
  24.                     if (in_array( $extension, $a ))
  25.                     {
  26.                         return $a[0];
  27.                     }
  28.                 }
  29.         }
  30.         return ''; // if nothing was found
  31.     }
  32.     /**
  33.     * Return an array describing the file which is stored in a page.
  34.     *
  35.     * @author  {@link http://wikkawiki.org/ChewBakka ChewBakka} (first draft)
  36.     * @input   $tag name of the page; default = current page.
  37.     * @output  Array or (if no file in page) null. Keys:
  38.     *          extension     file extension, e.g. 'png', 'jpg', 'ogg'
  39.     *          content-type  mime content type, e.g. 'image/png'
  40.     *          uploaded      when and who,. e.g. '2007-01-31 ChewBakka'
  41.     *          image         'yes' or 'no'
  42.     *          width         Width in pixels (images only)
  43.     *          height        Height in pixels (images only)
  44.     *          filename      PageName.extension
  45.     *          path          upload_path/PageName.extension
  46.     *          url           'http://..../PageName/file?action=get'
  47.     */
  48.     function GetFile( $tag = '' )
  49.     {
  50.         $data = null; // this variable will be returned
  51.         if (!$tag) $tag = $this->tag;
  52.         $metafile = $this->config['upload_path'].'/'.$tag.'.file'// metadata
  53.         if (file_exists($metafile) && $contents = file_get_contents($metafile))
  54.            {
  55.             $lines = explode( "\n", $contents );
  56.             // Lines look like "key: value" -> convert into array
  57.             $data = array(
  58.                 'extension'    => '',
  59.                 'content-type' => '',
  60.                 'uploaded'     => '<unknown>        <unknown>',
  61.                 'image'        => 'false',
  62.                 'width'        => '',
  63.                 'height'       => '',
  64.                 'filename'     => '',
  65.                 'path'         => '',
  66.                 'url'          => ''
  67.             );
  68.             foreach ($lines as $line)
  69.                 $a = explode( ':', trim($line), 2 );
  70.                 if( count($a) == 2 )
  71.                 {
  72.                     $data[ $a[0] ] = trim( $a[1] );
  73.                 }
  74.             // Convenient attributes which can not be stored permanently
  75.             $data['filename'] = $tag . '.' . $data['extension'];
  76.             $data['path'] = $this->config['upload_path'] .'/' . $data['filename'];
  77.             $data['url'] = $this->config['base_url'] . $tag'/file' .
  78.                 ($this->config['rewrite_mode']=='1' ? '?' : '&') .
  79.                 'action=get';
  80.             // Final check: file must exist.
  81.             if (! file_exists( $data['path'] ) )
  82.                 $data = null;
  83.         }
  84.         return $data;
  85.     }
  86.     /**
  87.     * Remove the file from the current page.
  88.     *
  89.     * @author  {@link http://wikkawiki.org/ChewBakka ChewBakka} (first draft)
  90.     * @input   none
  91.     * @output  none
  92.     */
  93.     function RemoveFile()
  94.     {
  95.         if ($data = $this->GetFile())
  96.         {
  97.             unlink( $this->config['upload_path'] . '/' . $this->tag . '.file' );
  98.             unlink( $this->config['upload_path'] . '/' . $data['filename'] );
  99.         }
  100.     }
  101.     /**
  102.     * Store an http-uploaded file in the current page.
  103.     * Any previous file will be replaced with the new file.
  104.     *
  105.     * @author  {@link http://wikkawiki.org/ChewBakka ChewBakka} (first draft)
  106.     * @input   $uploaded_file An item from PHP's $_FILES array (see there)
  107.     * @output  None
  108.     */
  109.     function SaveFile( $uploaded_file )
  110.     {
  111.         $this->RemoveFile();
  112.         $uploaded_file['name'] = strtolower( $uploaded_file['name'] );
  113.         $pathinfo = pathinfo( $uploaded_file['name'] );
  114.         $extension = $pathinfo['extension'];
  115.         if ($extension=='gz') {
  116.             if( count($a = explode( '.', $uploaded_file['name'])) > 2)
  117.                 $extension = $a[count($a)-2] . '.gz';
  118.             }           
  119.         }
  120.         $pathname = $this->config['upload_path'] . '/' . $this->tag;
  121.         $path = $pathname .