2008-05-14 15:54:36 +01:00
< ? php
2009-01-18 17:06:38 +00:00
/**
* Laconica , the distributed open - source microblogging tool
2008-05-20 20:14:12 +01:00
*
2009-01-18 17:06:38 +00:00
* Handler for posting new notices
*
* PHP version 5
*
* LICENCE : This program is free software : you can redistribute it and / or modify
2008-05-14 20:26:48 +01:00
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation , either version 3 of the License , or
* ( at your option ) any later version .
2008-05-20 20:14:12 +01:00
*
2008-05-14 20:26:48 +01:00
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
2009-01-18 17:06:38 +00:00
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
2008-05-14 20:26:48 +01:00
* GNU Affero General Public License for more details .
2008-05-20 20:14:12 +01:00
*
2008-05-14 20:26:48 +01:00
* You should have received a copy of the GNU Affero General Public License
2009-01-18 17:06:38 +00:00
* along with this program . If not , see < http :// www . gnu . org / licenses />.
*
* @ category Personal
* @ package Laconica
* @ author Evan Prodromou < evan @ controlyourself . ca >
* @ author Zach Copley < zach @ controlyourself . ca >
* @ author Sarven Capadisli < csarven @ controlyourself . ca >
* @ copyright 2008 - 2009 Control Yourself , Inc .
* @ license http :// www . fsf . org / licensing / licenses / agpl - 3.0 . html GNU Affero General Public License version 3.0
* @ link http :// laconi . ca /
2008-05-14 20:26:48 +01:00
*/
2009-01-18 17:06:38 +00:00
if ( ! defined ( 'LACONICA' )) {
exit ( 1 );
}
require_once INSTALLDIR . '/lib/noticelist.php' ;
2008-05-14 15:54:36 +01:00
2009-01-18 17:06:38 +00:00
/**
* Action for posting new notices
*
* @ category Personal
* @ package Laconica
* @ author Evan Prodromou < evan @ controlyourself . ca >
* @ author Zach Copley < zach @ controlyourself . ca >
* @ author Sarven Capadisli < csarven @ controlyourself . ca >
* @ license http :// www . fsf . org / licensing / licenses / agpl - 3.0 . html GNU Affero General Public License version 3.0
* @ link http :// laconi . ca /
*/
2008-12-11 23:20:00 +00:00
2008-12-23 19:49:23 +00:00
class NewnoticeAction extends Action
{
2009-01-18 17:06:38 +00:00
/**
* Error message , if any
*/
var $msg = null ;
/**
* Title of the page
*
* Note that this usually doesn ' t get called unless something went wrong
*
* @ return string page title
*/
function title ()
{
return _ ( 'New notice' );
}
/**
* Handle input , produce output
*
* Switches based on GET or POST method . On GET , shows a form
* for posting a notice . On POST , saves the results of that form .
*
* Results may be a full page , or just a single notice list item ,
* depending on whether AJAX was requested .
*
* @ param array $args $_REQUEST contents
*
* @ return void
*/
2008-11-11 02:23:30 +00:00
2008-12-23 19:33:23 +00:00
function handle ( $args )
{
2008-12-23 19:19:07 +00:00
if ( ! common_logged_in ()) {
2009-01-15 23:03:38 +00:00
$this -> clientError ( _ ( 'Not logged in.' ));
2008-12-23 19:19:07 +00:00
} else if ( $_SERVER [ 'REQUEST_METHOD' ] == 'POST' ) {
2009-05-31 21:42:29 +01:00
// check for this before token since all POST and FILES data
// is losts when size is exceeded
if ( empty ( $_POST ) && $_SERVER [ 'CONTENT_LENGTH' ]) {
$this -> clientError ( sprintf ( _ ( 'The server was unable to handle ' .
'that much POST data (%s bytes) due to its current configuration.' ),
$_SERVER [ 'CONTENT_LENGTH' ]));
}
parent :: handle ( $args );
2008-12-23 19:19:07 +00:00
2009-02-04 19:55:22 +00:00
// CSRF protection
2008-12-23 19:19:07 +00:00
$token = $this -> trimmed ( 'token' );
if ( ! $token || $token != common_session_token ()) {
2009-01-18 17:06:38 +00:00
$this -> clientError ( _ ( 'There was a problem with your session token. ' .
'Try again, please.' ));
2008-12-23 19:19:07 +00:00
}
2009-02-13 15:52:26 +00:00
try {
$this -> saveNewNotice ();
} catch ( Exception $e ) {
$this -> showForm ( $e -> getMessage ());
return ;
}
2008-12-23 19:19:07 +00:00
} else {
2009-01-18 17:06:38 +00:00
$this -> showForm ();
2008-12-23 19:19:07 +00:00
}
}
2009-05-31 21:42:29 +01:00
function isSupportedFileType () {
require_once 'MIME/Type.php' ;
$filetype = MIME_Type :: autoDetect ( $_FILES [ 'attach' ][ 'tmp_name' ]);
if ( in_array ( $filetype , common_config ( 'attachments' , 'supported' ))) {
return true ;
}
$media = MIME_Type :: getMedia ( $filetype );
if ( 'application' !== $media ) {
$hint = sprintf ( _ ( ' Try using another %s format.' ), $media );
} else {
$hint = '' ;
}
$this -> clientError ( sprintf (
_ ( '%s is not a supported filetype on this server.' ), $filetype ) . $hint );
}
function isRespectsQuota ( $user ) {
if ( $_FILES [ 'attach' ][ 'size' ] > common_config ( 'attachments' , 'file_quota' )) {
$this -> clientError ( sprintf ( _ ( 'No file may be larger than %d bytes ' .
'and the file you sent was %d bytes. Try to upload a smaller version.' ),
common_config ( 'attachments' , 'file_quota' ), $_FILES [ 'attach' ][ 'size' ]));
}
$query = " select sum(size) as total from file join file_to_post on file_to_post.file_id = file.id join notice on file_to_post.post_id = notice.id where profile_id = { $user -> id } and file.url like '%/notice/%/file' " ;
$file = new File ;
$file -> query ( $query );
$file -> fetch ();
$total = $file -> total + $_FILES [ 'attach' ][ 'size' ];
if ( $total > common_config ( 'attachments' , 'user_quota' )) {
$this -> clientError ( sprintf ( _ ( 'A file this large would exceed your user quota of %d bytes.' ), common_config ( 'attachments' , 'user_quota' )));
}
$query .= ' month(modified) = month(now()) and year(modified) = year(now())' ;
$file2 = new File ;
$file2 -> query ( $query );
$file2 -> fetch ();
$total2 = $file2 -> total + $_FILES [ 'attach' ][ 'size' ];
if ( $total2 > common_config ( 'attachments' , 'monthly_quota' )) {
$this -> clientError ( sprintf ( _ ( 'A file this large would exceed your monthly quota of %d bytes.' ), common_config ( 'attachments' , 'monthly_quota' )));
}
return true ;
}
function isValidFileAttached ( $user ) {
return isset ( $_FILES [ 'attach' ][ 'error' ])
&& ( $_FILES [ 'attach' ][ 'error' ] === UPLOAD_ERR_OK )
&& $this -> isSupportedFileType ()
&& $this -> isRespectsQuota ( $user );
2009-05-27 02:20:04 +01:00
}
2009-01-18 17:06:38 +00:00
/**
* Save a new notice , based on arguments
*
* If successful , will show the notice , or return an Ajax - y result .
* If not , it will show an error message -- possibly Ajax - y .
*
* Also , if the notice input looks like a command , it will run the
* command and show the results -- again , possibly ajaxy .
*
* @ return void
*/
2008-12-23 19:19:07 +00:00
2009-01-18 17:06:38 +00:00
function saveNewNotice ()
{
2008-12-23 19:19:07 +00:00
$user = common_current_user ();
2009-01-18 17:06:38 +00:00
assert ( $user ); // XXX: maybe an error instead...
2008-12-23 19:19:07 +00:00
$content = $this -> trimmed ( 'status_textarea' );
if ( ! $content ) {
2009-02-13 15:52:26 +00:00
$this -> clientError ( _ ( 'No content!' ));
2008-12-23 19:19:07 +00:00
} else {
$content_shortened = common_shorten_links ( $content );
if ( mb_strlen ( $content_shortened ) > 140 ) {
2009-02-13 15:52:26 +00:00
$this -> clientError ( _ ( 'That\'s too long. ' .
'Max notice size is 140 chars.' ));
2008-12-23 19:19:07 +00:00
}
}
$inter = new CommandInterpreter ();
$cmd = $inter -> handle_command ( $user , $content_shortened );
if ( $cmd ) {
if ( $this -> boolean ( 'ajax' )) {
2009-02-04 12:59:30 +00:00
$cmd -> execute ( new AjaxWebChannel ( $this ));
2008-12-23 19:19:07 +00:00
} else {
2009-02-04 12:59:30 +00:00
$cmd -> execute ( new WebChannel ( $this ));
2008-12-23 19:19:07 +00:00
}
return ;
}
$replyto = $this -> trimmed ( 'inreplyto' );
2009-03-03 21:33:52 +00:00
#If an ID of 0 is wrongly passed here, it will cause a database error,
#so override it...
if ( $replyto == 0 ) {
$replyto = 'false' ;
}
2008-12-23 19:19:07 +00:00
2009-05-31 21:42:29 +01:00
switch ( $_FILES [ 'attach' ][ 'error' ]) {
case UPLOAD_ERR_NO_FILE :
// no file uploaded
// nothing to do
break ;
case UPLOAD_ERR_OK :
// file was uploaded alright
// lets check if we really support its format
// and it doesn't go over quotas
if ( ! $this -> isValidFileAttached ( $user )) {
die ( 'clientError() should trigger an exception before reaching here.' );
}
break ;
case UPLOAD_ERR_INI_SIZE :
$this -> clientError ( _ ( 'The uploaded file exceeds the upload_max_filesize directive in php.ini.' ));
case UPLOAD_ERR_FORM_SIZE :
$this -> clientError ( _ ( 'The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form.' ));
case UPLOAD_ERR_PARTIAL :
$this -> clientError ( _ ( 'The uploaded file was only partially uploaded.' ));
case UPLOAD_ERR_NO_TMP_DIR :
$this -> clientError ( _ ( 'Missing a temporary folder.' ));
case UPLOAD_ERR_CANT_WRITE :
$this -> clientError ( _ ( 'Failed to write file to disk.' ));
case UPLOAD_ERR_EXTENSION :
$this -> clientError ( _ ( 'File upload stopped by extension.' ));
default :
die ( 'Should never reach here.' );
}
2009-05-13 19:27:32 +01:00
$notice = Notice :: saveNew ( $user -> id , $content_shortened , 'web' , 1 ,
2009-01-18 17:06:38 +00:00
( $replyto == 'false' ) ? null : $replyto );
2008-12-23 19:19:07 +00:00
if ( is_string ( $notice )) {
2009-02-13 15:52:26 +00:00
$this -> clientError ( $notice );
2008-12-23 19:19:07 +00:00
}
2009-05-31 21:42:29 +01:00
$this -> storeFile ( $notice );
2009-05-11 18:45:00 +01:00
$this -> saveUrls ( $notice );
2008-12-23 19:19:07 +00:00
common_broadcast_notice ( $notice );
if ( $this -> boolean ( 'ajax' )) {
2009-02-02 20:47:57 +00:00
$this -> startHTML ( 'text/xml;charset=utf-8' );
2009-01-15 22:57:15 +00:00
$this -> elementStart ( 'head' );
$this -> element ( 'title' , null , _ ( 'Notice posted' ));
$this -> elementEnd ( 'head' );
$this -> elementStart ( 'body' );
2009-01-18 17:06:38 +00:00
$this -> showNotice ( $notice );
2009-01-15 22:57:15 +00:00
$this -> elementEnd ( 'body' );
$this -> elementEnd ( 'html' );
2008-12-23 19:19:07 +00:00
} else {
$returnto = $this -> trimmed ( 'returnto' );
if ( $returnto ) {
$url = common_local_url ( $returnto ,
array ( 'nickname' => $user -> nickname ));
} else {
$url = common_local_url ( 'shownotice' ,
array ( 'notice' => $notice -> id ));
}
common_redirect ( $url , 303 );
}
}
2009-05-27 02:20:04 +01:00
function storeFile ( $notice ) {
2009-05-31 21:42:29 +01:00
if ( UPLOAD_ERR_NO_FILE === $_FILES [ 'attach' ][ 'error' ]) return ;
2009-05-27 02:20:04 +01:00
$filename = basename ( $_FILES [ 'attach' ][ 'name' ]);
$destination = " file/ { $notice -> id } - $filename " ;
if ( move_uploaded_file ( $_FILES [ 'attach' ][ 'tmp_name' ], INSTALLDIR . " / $destination " )) {
$file = new File ;
2009-05-27 08:47:45 +01:00
$file -> url = common_local_url ( 'file' , array ( 'notice' => $notice -> id ));
2009-05-27 02:20:04 +01:00
$file -> size = filesize ( INSTALLDIR . " / $destination " );
$file -> date = time ();
$file -> mimetype = $_FILES [ 'attach' ][ 'type' ];
2009-05-27 08:47:45 +01:00
if ( $file_id = $file -> insert ()) {
$file_redir = new File_redirection ;
$file_redir -> url = common_path ( $destination );
$file_redir -> file_id = $file_id ;
$file_redir -> insert ();
2009-05-27 02:20:04 +01:00
$f2p = new File_to_post ;
2009-05-27 08:47:45 +01:00
$f2p -> file_id = $file_id ;
2009-05-27 02:20:04 +01:00
$f2p -> post_id = $notice -> id ;
$f2p -> insert ();
} else {
2009-05-31 21:42:29 +01:00
$this -> clientError ( _ ( 'There was a database error while saving your file. Please try again.' ));
2009-05-27 02:20:04 +01:00
}
}
}
2009-05-11 18:45:00 +01:00
/** save all urls in the notice to the db
*
* follow redirects and save all available file information
* ( mimetype , date , size , oembed , etc . )
*
* @ param class $ notice Notice to pull URLs from
*
* @ return void
*/
2009-05-27 02:20:04 +01:00
function saveUrls ( $notice , $uploaded = null ) {
2009-05-11 18:45:00 +01:00
common_replace_urls_callback ( $notice -> content , array ( $this , 'saveUrl' ), $notice -> id );
}
function saveUrl ( $data ) {
list ( $url , $notice_id ) = $data ;
2009-05-13 19:27:32 +01:00
$zzz = File :: processNew ( $url , $notice_id );
2009-05-11 18:45:00 +01:00
}
2009-01-18 17:06:38 +00:00
/**
* Show an Ajax - y error message
*
* Goes back to the browser , where it ' s shown in a popup .
*
* @ param string $msg Message to show
*
* @ return void
*/
function ajaxErrorMsg ( $msg )
2008-12-23 19:33:23 +00:00
{
2009-02-03 21:46:09 +00:00
$this -> startHTML ( 'text/xml;charset=utf-8' , true );
2009-01-15 22:57:15 +00:00
$this -> elementStart ( 'head' );
$this -> element ( 'title' , null , _ ( 'Ajax Error' ));
$this -> elementEnd ( 'head' );
$this -> elementStart ( 'body' );
$this -> element ( 'p' , array ( 'id' => 'error' ), $msg );
$this -> elementEnd ( 'body' );
$this -> elementEnd ( 'html' );
2008-12-23 19:19:07 +00:00
}
2009-01-18 17:06:38 +00:00
/**
* Formerly page output
*
* This used to be the whole page output ; now that ' s been largely
* subsumed by showPage . So this just stores an error message , if
* it was passed , and calls showPage .
*
* Note that since we started doing Ajax output , this page is rarely
* seen .
*
* @ param string $msg An error message , if any
*
* @ return void
*/
2008-12-23 19:19:07 +00:00
2009-01-18 17:06:38 +00:00
function showForm ( $msg = null )
2008-12-23 19:33:23 +00:00
{
2008-12-23 19:19:07 +00:00
if ( $msg && $this -> boolean ( 'ajax' )) {
2009-01-18 17:06:38 +00:00
$this -> ajaxErrorMsg ( $msg );
2008-12-23 19:19:07 +00:00
return ;
}
2009-01-18 17:06:38 +00:00
$this -> msg = $msg ;
$this -> showPage ();
}
/**
* Overload for replies or bad results
*
* We show content in the notice form if there were replies or results .
*
* @ return void
*/
function showNoticeForm ()
{
2008-12-23 19:19:07 +00:00
$content = $this -> trimmed ( 'status_textarea' );
if ( ! $content ) {
$replyto = $this -> trimmed ( 'replyto' );
$profile = Profile :: staticGet ( 'nickname' , $replyto );
if ( $profile ) {
$content = '@' . $profile -> nickname . ' ' ;
}
}
2009-01-18 17:06:38 +00:00
2009-02-22 12:32:14 +00:00
$notice_form = new NoticeForm ( $this , '' , $content );
2009-01-18 17:06:38 +00:00
$notice_form -> show ();
}
/**
* Show an error message
*
* Shows an error message if there is one .
*
* @ return void
*
* @ todo maybe show some instructions ?
*/
function showPageNotice ()
{
if ( $this -> msg ) {
$this -> element ( 'p' , array ( 'id' => 'error' ), $this -> msg );
2008-12-23 19:19:07 +00:00
}
}
2009-01-18 17:06:38 +00:00
/**
* Output a notice
*
* Used to generate the notice code for Ajax results .
*
* @ param Notice $notice Notice that was saved
*
* @ return void
*/
function showNotice ( $notice )
2008-12-23 19:33:23 +00:00
{
2009-01-18 17:06:38 +00:00
$nli = new NoticeListItem ( $notice , $this );
2008-12-11 23:20:00 +00:00
$nli -> show ();
2008-12-23 19:19:07 +00:00
}
2008-06-20 08:17:00 +01:00
}