We try to handle DB_DataObject errors a little bit better. Previously, they just spit out a cryptic string to the browser with a suggestion to turn on debugging (not a good idea!). So, we catch the error, write the full error message to the log, and then tell users that the can contact the admins if they need to.
		
			
				
	
	
		
			370 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			370 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
| <?php
 | |
| /**
 | |
|  * Laconica, the distributed open-source microblogging tool
 | |
|  *
 | |
|  * Low-level generator for HTML
 | |
|  *
 | |
|  * PHP version 5
 | |
|  *
 | |
|  * LICENCE: This program is free software: you can redistribute it and/or modify
 | |
|  * 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.
 | |
|  *
 | |
|  * This program is distributed in the hope that it will be useful,
 | |
|  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | |
|  * GNU Affero General Public License for more details.
 | |
|  *
 | |
|  * You should have received a copy of the GNU Affero General Public License
 | |
|  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | |
|  *
 | |
|  * @category  Output
 | |
|  * @package   Laconica
 | |
|  * @author    Evan Prodromou <evan@controlyourself.ca>
 | |
|  * @author    Sarven Capadisli <csarven@controlyourself.ca>
 | |
|  * @copyright 2008 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/
 | |
|  */
 | |
| 
 | |
| if (!defined('LACONICA')) {
 | |
|     exit(1);
 | |
| }
 | |
| 
 | |
| require_once INSTALLDIR.'/lib/xmloutputter.php';
 | |
| 
 | |
| define('PAGE_TYPE_PREFS',
 | |
|        'text/html,application/xhtml+xml,'.
 | |
|        'application/xml;q=0.3,text/xml;q=0.2');
 | |
| 
 | |
| /**
 | |
|  * Low-level generator for HTML
 | |
|  *
 | |
|  * Abstracts some of the code necessary for HTML generation. Especially
 | |
|  * has methods for generating HTML form elements. Note that these have
 | |
|  * been created kind of haphazardly, not with an eye to making a general
 | |
|  * HTML-creation class.
 | |
|  *
 | |
|  * @category Output
 | |
|  * @package  Laconica
 | |
|  * @author   Evan Prodromou <evan@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/
 | |
|  *
 | |
|  * @see      Action
 | |
|  * @see      XMLOutputter
 | |
|  */
 | |
| 
 | |
| class HTMLOutputter extends XMLOutputter
 | |
| {
 | |
|     /**
 | |
|      * Constructor
 | |
|      *
 | |
|      * Just wraps the XMLOutputter constructor.
 | |
|      *
 | |
|      * @param string  $output URI to output to, default = stdout
 | |
|      * @param boolean $indent Whether to indent output, default true
 | |
|      */
 | |
| 
 | |
|     function __construct($output='php://output', $indent=true)
 | |
|     {
 | |
|         parent::__construct($output, $indent);
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Start an HTML document
 | |
|      *
 | |
|      * If $type isn't specified, will attempt to do content negotiation.
 | |
|      *
 | |
|      * Attempts to do content negotiation for language, also.
 | |
|      *
 | |
|      * @param string $type MIME type to use; default is to do negotation.
 | |
|      *
 | |
|      * @todo extract content negotiation code to an HTTP module or class.
 | |
|      *
 | |
|      * @return void
 | |
|      */
 | |
| 
 | |
|     function startHTML($type=null)
 | |
|     {
 | |
|         if (!$type) {
 | |
|             $httpaccept = isset($_SERVER['HTTP_ACCEPT']) ?
 | |
|               $_SERVER['HTTP_ACCEPT'] : null;
 | |
| 
 | |
|             // XXX: allow content negotiation for RDF, RSS, or XRDS
 | |
| 
 | |
|             $cp = common_accept_to_prefs($httpaccept);
 | |
|             $sp = common_accept_to_prefs(PAGE_TYPE_PREFS);
 | |
| 
 | |
|             $type = common_negotiate_type($cp, $sp);
 | |
| 
 | |
|             if (!$type) {
 | |
|                 common_user_error(_('This page is not available in a '.
 | |
|                                     'media type you accept'), 406);
 | |
|                 exit(0);
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         header('Content-Type: '.$type);
 | |
| 
 | |
|         $this->extraHeaders();
 | |
| 
 | |
|         $this->startXML('html',
 | |
|                         '-//W3C//DTD XHTML 1.0 Strict//EN',
 | |
|                         'http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd');
 | |
| 
 | |
|         $language = $this->getLanguage();
 | |
| 
 | |
|         $this->elementStart('html', array('xmlns' => 'http://www.w3.org/1999/xhtml',
 | |
|                                           'xml:lang' => $language,
 | |
|                                           'lang' => $language));
 | |
|     }
 | |
| 
 | |
|     function getLanguage()
 | |
|     {
 | |
|         // FIXME: correct language for interface
 | |
|         return common_language();
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|     *  Ends an HTML document
 | |
|     *
 | |
|     *  @return void
 | |
|     */
 | |
|     function endHTML()
 | |
|     {
 | |
|         $this->elementEnd('html');
 | |
|         $this->endXML();
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|     *  To specify additional HTTP headers for the action
 | |
|     *
 | |
|     *  @return void
 | |
|     */
 | |
|     function extraHeaders()
 | |
|     {
 | |
|         // Needs to be overloaded
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Output an HTML text input element
 | |
|      *
 | |
|      * Despite the name, it is specifically for outputting a
 | |
|      * text input element, not other <input> elements. It outputs
 | |
|      * a cluster of elements, including a <label> and an associated
 | |
|      * instructions span.
 | |
|      *
 | |
|      * @param string $id           element ID, must be unique on page
 | |
|      * @param string $label        text of label for the element
 | |
|      * @param string $value        value of the element, default null
 | |
|      * @param string $instructions instructions for valid input
 | |
|      *
 | |
|      * @todo add a $name parameter
 | |
|      * @todo add a $maxLength parameter
 | |
|      * @todo add a $size parameter
 | |
|      *
 | |
|      * @return void
 | |
|      */
 | |
| 
 | |
|     function input($id, $label, $value=null, $instructions=null)
 | |
|     {
 | |
|         $this->element('label', array('for' => $id), $label);
 | |
|         $attrs = array('name' => $id,
 | |
|                        'type' => 'text',
 | |
|                        'id' => $id);
 | |
|         if ($value) {
 | |
|             $attrs['value'] = $value;
 | |
|         }
 | |
|         $this->element('input', $attrs);
 | |
|         if ($instructions) {
 | |
|             $this->element('p', 'form_guide', $instructions);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * output an HTML checkbox and associated elements
 | |
|      *
 | |
|      * Note that the value is default 'true' (the string), which can
 | |
|      * be used by Action::boolean()
 | |
|      *
 | |
|      * @param string $id           element ID, must be unique on page
 | |
|      * @param string $label        text of label for the element
 | |
|      * @param string $checked      if the box is checked, default false
 | |
|      * @param string $instructions instructions for valid input
 | |
|      * @param string $value        value of the checkbox, default 'true'
 | |
|      * @param string $disabled     show the checkbox disabled, default false
 | |
|      *
 | |
|      * @return void
 | |
|      *
 | |
|      * @todo add a $name parameter
 | |
|      */
 | |
| 
 | |
|     function checkbox($id, $label, $checked=false, $instructions=null,
 | |
|                       $value='true', $disabled=false)
 | |
|     {
 | |
|         $attrs = array('name' => $id,
 | |
|                        'type' => 'checkbox',
 | |
|                        'class' => 'checkbox',
 | |
|                        'id' => $id);
 | |
|         if ($value) {
 | |
|             $attrs['value'] = $value;
 | |
|         }
 | |
|         if ($checked) {
 | |
|             $attrs['checked'] = 'checked';
 | |
|         }
 | |
|         if ($disabled) {
 | |
|             $attrs['disabled'] = 'true';
 | |
|         }
 | |
|         $this->element('input', $attrs);
 | |
|         $this->text(' ');
 | |
|         $this->element('label', array('class' => 'checkbox',
 | |
|                                       'for' => $id),
 | |
|                        $label);
 | |
|         $this->text(' ');
 | |
|         if ($instructions) {
 | |
|             $this->element('p', 'form_guide', $instructions);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * output an HTML combobox/select and associated elements
 | |
|      *
 | |
|      * $content is an array of key-value pairs for the dropdown, where
 | |
|      * the key is the option value attribute and the value is the option
 | |
|      * text. (Careful on the overuse of 'value' here.)
 | |
|      *
 | |
|      * @param string $id           element ID, must be unique on page
 | |
|      * @param string $label        text of label for the element
 | |
|      * @param array  $content      options array, value => text
 | |
|      * @param string $instructions instructions for valid input
 | |
|      * @param string $blank_select whether to have a blank entry, default false
 | |
|      * @param string $selected     selected value, default null
 | |
|      *
 | |
|      * @return void
 | |
|      *
 | |
|      * @todo add a $name parameter
 | |
|      */
 | |
| 
 | |
|     function dropdown($id, $label, $content, $instructions=null,
 | |
|                       $blank_select=false, $selected=null)
 | |
|     {
 | |
|         $this->element('label', array('for' => $id), $label);
 | |
|         $this->elementStart('select', array('id' => $id, 'name' => $id));
 | |
|         if ($blank_select) {
 | |
|             $this->element('option', array('value' => ''));
 | |
|         }
 | |
|         foreach ($content as $value => $option) {
 | |
|             if ($value == $selected) {
 | |
|                 $this->element('option', array('value' => $value,
 | |
|                                                'selected' => 'selected'),
 | |
|                                $option);
 | |
|             } else {
 | |
|                 $this->element('option', array('value' => $value), $option);
 | |
|             }
 | |
|         }
 | |
|         $this->elementEnd('select');
 | |
|         if ($instructions) {
 | |
|             $this->element('p', 'form_guide', $instructions);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * output an HTML hidden element
 | |
|      *
 | |
|      * $id is re-used as name
 | |
|      *
 | |
|      * @param string $id    element ID, must be unique on page
 | |
|      * @param string $value hidden element value, default null
 | |
|      * @param string $name  name, if different than ID
 | |
|      *
 | |
|      * @return void
 | |
|      */
 | |
| 
 | |
|     function hidden($id, $value, $name=null)
 | |
|     {
 | |
|         $this->element('input', array('name' => ($name) ? $name : $id,
 | |
|                                       'type' => 'hidden',
 | |
|                                       'id' => $id,
 | |
|                                       'value' => $value));
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * output an HTML password input and associated elements
 | |
|      *
 | |
|      * @param string $id           element ID, must be unique on page
 | |
|      * @param string $label        text of label for the element
 | |
|      * @param string $instructions instructions for valid input
 | |
|      *
 | |
|      * @return void
 | |
|      *
 | |
|      * @todo add a $name parameter
 | |
|      */
 | |
| 
 | |
|     function password($id, $label, $instructions=null)
 | |
|     {
 | |
|         $this->element('label', array('for' => $id), $label);
 | |
|         $attrs = array('name' => $id,
 | |
|                        'type' => 'password',
 | |
|                        'class' => 'password',
 | |
|                        'id' => $id);
 | |
|         $this->element('input', $attrs);
 | |
|         if ($instructions) {
 | |
|             $this->element('p', 'form_guide', $instructions);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * output an HTML submit input and associated elements
 | |
|      *
 | |
|      * @param string $id    element ID, must be unique on page
 | |
|      * @param string $label text of the button
 | |
|      * @param string $cls   class of the button, default 'submit'
 | |
|      * @param string $name  name, if different than ID
 | |
|      *
 | |
|      * @return void
 | |
|      *
 | |
|      * @todo add a $name parameter
 | |
|      */
 | |
| 
 | |
|     function submit($id, $label, $cls='submit', $name=null, $title=null)
 | |
|     {
 | |
|         $this->element('input', array('type' => 'submit',
 | |
|                                       'id' => $id,
 | |
|                                       'name' => ($name) ? $name : $id,
 | |
|                                       'class' => $cls,
 | |
|                                       'value' => $label,
 | |
|                                       'title' => $title));
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * output an HTML textarea and associated elements
 | |
|      *
 | |
|      * @param string $id           element ID, must be unique on page
 | |
|      * @param string $label        text of label for the element
 | |
|      * @param string $content      content of the textarea, default none
 | |
|      * @param string $instructions instructions for valid input
 | |
|      *
 | |
|      * @return void
 | |
|      *
 | |
|      * @todo add a $name parameter
 | |
|      * @todo add a $cols parameter
 | |
|      * @todo add a $rows parameter
 | |
|      */
 | |
| 
 | |
|     function textarea($id, $label, $content=null, $instructions=null)
 | |
|     {
 | |
|         $this->element('label', array('for' => $id), $label);
 | |
|         $this->element('textarea', array('rows' => 3,
 | |
|                                          'cols' => 40,
 | |
|                                          'name' => $id,
 | |
|                                          'id' => $id),
 | |
|                        ($content) ? $content : '');
 | |
|         if ($instructions) {
 | |
|             $this->element('p', 'form_guide', $instructions);
 | |
|         }
 | |
|     }
 | |
| }
 |