diff --git a/oss/vtiger/trunk/vtlib/ModuleDir/5.0.4/CallRelatedList.php b/oss/vtiger/trunk/vtlib/ModuleDir/5.0.4/CallRelatedList.php new file mode 100644 index 00000000..8517bc3f --- /dev/null +++ b/oss/vtiger/trunk/vtlib/ModuleDir/5.0.4/CallRelatedList.php @@ -0,0 +1,63 @@ +retrieve_entity_info($record, $currentModule); + $focus->id = $record; + } + + $smarty = new vtigerCRM_Smarty; + + if($isduplicate == 'true') $focus->id = ''; + if(isset($_REQUEST['mode']) && $_REQUEST['mode'] != ' ') $smarty->assign("OP_MODE",$_REQUEST['mode']); + if(!$_SESSION['rlvs'][$currentModule]) unset($_SESSION['rlvs']); + + // Identify this module as custom module. + $smarty->assign('CUSTOM_MODULE', true); + + $smarty->assign('APP', $app_strings); + $smarty->assign('MOD', $mod_strings); + $smarty->assign('MODULE', $currentModule); + // TODO: Update Single Module Instance name here. + $smarty->assign('SINGLE_MOD', $currentModule); + $smarty->assign('CATEGORY', $category); + $smarty->assign('IMAGE_PATH', "themes/$theme/images/"); + $smarty->assign('THEME', $theme); + $smarty->assign('ID', $focus->id); + $smarty->assign('MODE', $focus->mode); + $smarty->assign('CHECK', $tool_buttons); + + $smarty->assign('NAME', $focus->column_fields[$focus->def_detailview_recname]); + $smarty->assign('UPDATEINFO',updateInfo($focus->id)); + + $related_array = getRelatedLists($currentModule, $focus); + + $smarty->assign('RELATEDLISTS', $related_array); + $smarty->display('RelatedLists.tpl'); +} +?> \ No newline at end of file diff --git a/oss/vtiger/trunk/vtlib/ModuleDir/5.0.4/CustomView.php b/oss/vtiger/trunk/vtlib/ModuleDir/5.0.4/CustomView.php new file mode 100644 index 00000000..aebb8b53 --- /dev/null +++ b/oss/vtiger/trunk/vtlib/ModuleDir/5.0.4/CustomView.php @@ -0,0 +1,12 @@ + diff --git a/oss/vtiger/trunk/vtlib/ModuleDir/5.0.4/Delete.php b/oss/vtiger/trunk/vtlib/ModuleDir/5.0.4/Delete.php new file mode 100644 index 00000000..66c2ce14 --- /dev/null +++ b/oss/vtiger/trunk/vtlib/ModuleDir/5.0.4/Delete.php @@ -0,0 +1,29 @@ + \ No newline at end of file diff --git a/oss/vtiger/trunk/vtlib/ModuleDir/5.0.4/DetailView.php b/oss/vtiger/trunk/vtlib/ModuleDir/5.0.4/DetailView.php new file mode 100644 index 00000000..d76cc3f0 --- /dev/null +++ b/oss/vtiger/trunk/vtlib/ModuleDir/5.0.4/DetailView.php @@ -0,0 +1,83 @@ +id = $record; + $focus->retrieve_entity_info($record, $currentModule); +} +if($isduplicate == 'true') $focus->id = ''; + +// Identify this module as custom module. +$smarty->assign('CUSTOM_MODULE', true); + +$smarty->assign('APP', $app_strings); +$smarty->assign('MOD', $mod_strings); +$smarty->assign('MODULE', $currentModule); +// TODO: Update Single Module Instance name here. +$smarty->assign('SINGLE_MOD', $currentModule); +$smarty->assign('CATEGORY', $category); +$smarty->assign('IMAGE_PATH', "themes/$theme/images/"); +$smarty->assign('THEME', $theme); +$smarty->assign('ID', $focus->id); +$smarty->assign('MODE', $focus->mode); + +$recordName = array_values(getEntityName($currentModule, $focus->id)); +$recordName = $recordName[0]; +$smarty->assign('NAME', $recordName); +$smarty->assign('UPDATEINFO',updateInfo($focus->id)); + +$smarty->assign('IS_REL_LIST',isPresentRelatedLists($currentModule)); + +$validationArray = split_validationdataArray(getDBValidationData($focus->tab_name, $tabid)); +$smarty->assign('VALIDATION_DATA_FIELDNAME',$validationArray['fieldname']); +$smarty->assign('VALIDATION_DATA_FIELDDATATYPE',$validationArray['datatype']); +$smarty->assign('VALIDATION_DATA_FIELDLABEL',$validationArray['fieldlabel']); + +$smarty->assign('EDIT_PERMISSION', isPermitted($currentModule, 'EditView', $record)); +$smarty->assign('CHECK', $tool_buttons); + +$smarty->assign('IS_REL_LIST', isPresentRelatedLists($currentModule)); +$smarty->assign('SinglePane_View', $singlepane_view); + +if($singlepane_view == 'true') { + $related_array = getRelatedLists($currentModule,$focus); + $smarty->assign("RELATEDLISTS", $related_array); +} + +if(isPermitted($currentModule, 'EditView', $record) == 'yes') + $smarty->assign('EDIT_DUPLICATE', 'permitted'); +if(isPermitted($currentModule, 'Delete', $record) == 'yes') + $smarty->assign('DELETE', 'permitted'); + +$smarty->assign('BLOCKS', getBlocks($currentModule,'detail_view','',$focus->column_fields)); + +// Gather the custom link information to display +include_once('vtlib/Vtiger/Link.php'); +$customlink_params = Array('MODULE'=>$currentModule, 'RECORD'=>$focus->id, 'ACTION'=>$_REQUEST['action']); +$smarty->assign('CUSTOM_LINKS', Vtiger_Link::getAllByType(getTabid($currentModule), Array('DETAILVIEWBASIC','DETAILVIEW'), $customlink_params)); +// END + +$smarty->display('DetailView.tpl'); + +?> \ No newline at end of file diff --git a/oss/vtiger/trunk/vtlib/ModuleDir/5.0.4/DetailViewAjax.php b/oss/vtiger/trunk/vtlib/ModuleDir/5.0.4/DetailViewAjax.php new file mode 100644 index 00000000..105690de --- /dev/null +++ b/oss/vtiger/trunk/vtlib/ModuleDir/5.0.4/DetailViewAjax.php @@ -0,0 +1,41 @@ +retrieve_entity_info($crmid, $currentModule); + $modObj->column_fields[$fieldname] = $fieldvalue; + $modObj->id = $crmid; + $modObj->mode = 'edit'; + $modObj->save($currentModule); + if($modObj->id != '') + { + echo ':#:SUCCESS'; + }else + { + echo ':#:FAILURE'; + } + }else + { + echo ':#:FAILURE'; + } +} +?> diff --git a/oss/vtiger/trunk/vtlib/ModuleDir/5.0.4/EditView.php b/oss/vtiger/trunk/vtlib/ModuleDir/5.0.4/EditView.php new file mode 100644 index 00000000..5e1f2192 --- /dev/null +++ b/oss/vtiger/trunk/vtlib/ModuleDir/5.0.4/EditView.php @@ -0,0 +1,88 @@ +id = $record; + $focus->mode = 'edit'; + $focus->retrieve_entity_info($record, $currentModule); +} +if($isduplicate == 'true') { + $focus->id = ''; + $focus->mode = ''; +} + +$disp_view = getView($focus->mode); +if($disp_view == 'edit_view') + $smarty->assign('BLOCKS', getBlocks($currentModule, $disp_view, $focus->mode, $focus->column_fields)); +else + $smarty->assign('BASBLOCKS', getBlocks($currentModule, $disp_view, $focus->mode, $focus->column_fields, 'BAS')); + +$smarty->assign('OP_MODE',$disp_view); +$smarty->assign('APP', $app_strings); +$smarty->assign('MOD', $mod_strings); +$smarty->assign('MODULE', $currentModule); +// TODO: Update Single Module Instance name here. +$smarty->assign('SINGLE_MOD', $currentModule); +$smarty->assign('CATEGORY', $category); +$smarty->assign("THEME", $theme); +$smarty->assign('IMAGE_PATH', "themes/$theme/images/"); +$smarty->assign('ID', $focus->id); +$smarty->assign('MODE', $focus->mode); + +$smarty->assign('CHECK', Button_Check($currentModule)); +$smarty->assign('DUPLICATE', $isduplicate); + +if($focus->mode == 'edit') { + $recordName = array_values(getEntityName($currentModule, $focus->id)); + $recordName = $recordName[0]; + $smarty->assign('NAME', $recordName); + $smarty->assign('UPDATEINFO',updateInfo($focus->id)); +} else if($isduplicate) { + $recordName = array_values(getEntityName($currentModule, $record)); + $recordName = $recordName[0]; + $smarty->assign('NAME', $recordName); +} + +if(isset($_REQUEST['return_module'])) $smarty->assign("RETURN_MODULE", $_REQUEST['return_module']); +if(isset($_REQUEST['return_action'])) $smarty->assign("RETURN_ACTION", $_REQUEST['return_action']); +if(isset($_REQUEST['return_id'])) $smarty->assign("RETURN_ID", $_REQUEST['return_id']); +if (isset($_REQUEST['return_viewname'])) $smarty->assign("RETURN_VIEWNAME", $_REQUEST['return_viewname']); + +// Field Validation Information +$tabid = getTabid($currentModule); +$validationData = getDBValidationData($focus->tab_name,$tabid); +$validationArray = split_validationdataArray($validationData); + +$smarty->assign("VALIDATION_DATA_FIELDNAME",$validationArray['fieldname']); +$smarty->assign("VALIDATION_DATA_FIELDDATATYPE",$validationArray['datatype']); +$smarty->assign("VALIDATION_DATA_FIELDLABEL",$validationArray['fieldlabel']); + +// In case you have a date field +$smarty->assign("CALENDAR_LANG", $app_strings['LBL_JSCALENDAR_LANG']); + +// Gather the help information associated with fields +$smarty->assign('FIELDHELPINFO', vtlib_getFieldHelpInfo($currentModule)); +// END + +if($focus->mode == 'edit') $smarty->display('salesEditView.tpl'); +else $smarty->display('CreateView.tpl'); + +?> \ No newline at end of file diff --git a/oss/vtiger/trunk/vtlib/ModuleDir/5.0.4/ExportRecords.php b/oss/vtiger/trunk/vtlib/ModuleDir/5.0.4/ExportRecords.php new file mode 100644 index 00000000..31029bc0 --- /dev/null +++ b/oss/vtiger/trunk/vtlib/ModuleDir/5.0.4/ExportRecords.php @@ -0,0 +1,12 @@ + diff --git a/oss/vtiger/trunk/vtlib/ModuleDir/5.0.4/Import.php b/oss/vtiger/trunk/vtlib/ModuleDir/5.0.4/Import.php new file mode 100644 index 00000000..576068f5 --- /dev/null +++ b/oss/vtiger/trunk/vtlib/ModuleDir/5.0.4/Import.php @@ -0,0 +1,12 @@ + diff --git a/oss/vtiger/trunk/vtlib/ModuleDir/5.0.4/ListView.php b/oss/vtiger/trunk/vtlib/ModuleDir/5.0.4/ListView.php new file mode 100644 index 00000000..048f93f0 --- /dev/null +++ b/oss/vtiger/trunk/vtlib/ModuleDir/5.0.4/ListView.php @@ -0,0 +1,154 @@ +getSortOrder(); +$order_by = $focus->getOrderBy(); + +$_SESSION[$currentModule."_Order_by"] = $order_by; +$_SESSION[$currentModule."_Sort_Order"]=$sorder; + +$smarty = new vtigerCRM_Smarty(); + +// Identify this module as custom module. +$smarty->assign('CUSTOM_MODULE', true); + +$smarty->assign('MOD', $mod_strings); +$smarty->assign('APP', $app_strings); +$smarty->assign('MODULE', $currentModule); +$smarty->assign('SINGLE_MOD', $currentModule); +$smarty->assign('CATEGORY', $category); +$smarty->assign('BUTTONS', $list_buttons); +$smarty->assign('CHECK', $tool_buttons); +$smarty->assign("THEME", $theme); +$smarty->assign('IMAGE_PATH', "themes/$theme/images/"); + +$smarty->assign('CHANGE_OWNER', getUserslist()); +$smarty->assign('CHANGE_GROUP_OWNER', getGroupslist()); + +// Enabling Module Search +$url_string = ''; +if($_REQUEST['query'] == 'true') { + list($where, $ustring) = split('#@@#', getWhereCondition($currentModule)); + $url_string .= "&query=true$ustring"; + $smarty->assign('SEARCH_URL', $url_string); +} + +// Custom View +$customView = new CustomView($currentModule); +$viewid = $customView->getViewId($currentModule); +$customview_html = $customView->getCustomViewCombo($viewid); +$viewinfo = $customView->getCustomViewByCvid($viewid); + +$smarty->assign("VIEWID", $viewid); + +if($viewinfo['viewname'] == 'All') $smarty->assign('ALL', 'All'); + +if($viewid != '0') { + $listquery = getListQuery($currentModule); + $list_query= $customView->getModifiedCvListQuery($viewid, $listquery, $currentModule); +} else { + $list_query= getListQuery($currentModule); +} + +if($where != '') { + $list_query = "$list_query AND $where"; +} + +// Sorting +if($order_by) { + if($order_by == 'smownerid') $list_query .= ' ORDER BY user_name '.$sorder; + else { + $tablename = getTableNameForField($currentModule, $order_by); + $tablename = ($tablename != '')? ($tablename . '.') : ''; + $list_query .= ' ORDER BY ' . $tablename . $order_by . ' ' . $sorder; + } +} + +$countQuery = $adb->query( mkCountQuery($list_query) ); +$recordCount= $adb->query_result($countQuery,0,'count'); + +// Set paging start value. +$start = 1; +if(isset($_REQUEST['start'])) { $start = $_REQUEST['start']; } +else { $start = $_SESSION['lvs'][$currentModule]['start']; } +// Total records is less than a page now. +if($recordCount <= $list_max_entries_per_page) $start = 1; + +// Save in session +if(empty($start)) $start = 1; // Reset to proper state +$_SESSION['lvs'][$currentModule]['start'] = $start; + +$navigation_array = getNavigationValues($start, $recordCount, $list_max_entries_per_page); + +$start_rec = $navigation_array['start']; +$end_rec = $navigation_array['end_val']; +$_SESSION['nav_start']=$start_rec; +$_SESSION['nav_end']=$end_rec; + +if ($start_rec ==0) $limit_start_rec = 0; +else $limit_start_rec = $start_rec -1; + +$list_result = $adb->query( $list_query . " LIMIT $limit_start_rec, $list_max_entries_per_page" ); + +$record_string= $app_strings['LBL_SHOWING']." $start_rec - $end_rec " . $app_strings['LBL_LIST_OF'] ." ".$recordCount; + +$smarty->assign('RECORD_COUNTS', $record_string); +$smarty->assign("CUSTOMVIEW_OPTION",$customview_html); + +// Navigation +$start = $_SESSION['lvs'][$currentModule]['start']; +$navigation_array = getNavigationValues($start, $recordCount, $list_max_entries_per_page); +$navigationOutput = getTableHeaderNavigation($navigation_array, $url_string, $currentModule, 'index', $viewid); +$smarty->assign("NAVIGATION", $navigationOutput); + +$listview_header = getListViewHeader($focus,$currentModule,$url_string,$sorder,$order_by,'',$customView); +$listview_entries = getListViewEntries($focus,$currentModule,$list_result,$navigation_array,'','','EditView','Delete',$customView); +$listview_header_search = getSearchListHeaderValues($focus,$currentModule,$url_string,$sorder,$order_by,'',$customView); + +$smarty->assign('LISTHEADER', $listview_header); +$smarty->assign('LISTENTITY', $listview_entries); +$smarty->assign('SEARCHLISTHEADER',$listview_header_search); + +// Module Search +$alphabetical = AlphabeticalSearch($currentModule,'index',$focus->def_basicsearch_col,'true','basic','','','','',$viewid); +$fieldnames = getAdvSearchfields($currentModule); +$criteria = getcriteria_options(); +$smarty->assign("ALPHABETICAL", $alphabetical); +$smarty->assign("FIELDNAMES", $fieldnames); +$smarty->assign("CRITERIA", $criteria); + +if(isset($_REQUEST['ajax']) && $_REQUEST['ajax'] != '') + $smarty->display("ListViewEntries.tpl"); +else + $smarty->display('ListView.tpl'); + +?> diff --git a/oss/vtiger/trunk/vtlib/ModuleDir/5.0.4/ModuleFile.js b/oss/vtiger/trunk/vtlib/ModuleDir/5.0.4/ModuleFile.js new file mode 100644 index 00000000..3fd0758c --- /dev/null +++ b/oss/vtiger/trunk/vtlib/ModuleDir/5.0.4/ModuleFile.js @@ -0,0 +1,8 @@ +/*+********************************************************************************** + * The contents of this file are subject to the vtiger CRM Public License Version 1.0 + * ("License"); You may not use this file except in compliance with the License + * The Original Code is: vtiger CRM Open Source + * The Initial Developer of the Original Code is vtiger. + * Portions created by vtiger are Copyright (C) vtiger. + * All Rights Reserved. + ************************************************************************************/ diff --git a/oss/vtiger/trunk/vtlib/ModuleDir/5.0.4/ModuleFile.php b/oss/vtiger/trunk/vtlib/ModuleDir/5.0.4/ModuleFile.php new file mode 100644 index 00000000..46bf4ac2 --- /dev/null +++ b/oss/vtiger/trunk/vtlib/ModuleDir/5.0.4/ModuleFile.php @@ -0,0 +1,366 @@ + 'crmid', + 'vtiger_payslip' => 'payslipid', + 'vtiger_payslipcf' => 'payslipid'); + + // Mandatory for Listing + var $list_fields = Array ( + // Field Label=> Array(tablename, columnname) + 'Payslip Name'=> Array('payslip', 'payslipname'), + 'Assigned To' => Array('crmentity','smownerid') + ); + var $list_fields_name = Array( + // Field Label=>fieldname + 'Payslip Name'=> 'payslipname', + 'Assigned To' => 'assigned_user_id' + ); + + // Make the field link detail view from list view (Fieldname) + var $list_link_field = 'payslipname'; + + // For Popup listview + var $search_fields = Array( + 'Payslip Name'=> Array('payslip', 'payslipname') + ); + var $search_fields_name = Array( + 'Payslip Name'=> 'payslipname' + ); + + var $popup_fields = Array('payslipname'); + + var $sortby_fields = Array('payslipname', 'payslipmonth', 'smownerid', 'modifiedtime'); + + // For alphabetical search + var $def_basicsearch_col = 'payslipname'; + + // Column value to use on detail view record text display. + var $def_detailview_recname = 'payslipname'; + + // Required information for enabling Import feature + var $required_fields = Array('payslipname'=>1); + + // Callback function list during Importing + var $special_functions = array("set_import_assigned_user"); + + var $default_order_by = 'payslipname'; + var $default_sort_order='ASC'; + + function __construct() { + global $log, $currentModule; + $this->column_fields = getColumnFields($currentModule); + $this->db = new PearDatabase(); + $this->log = $log; + } + + function getSortOrder() { + global $currentModule; + + $sortorder = $this->default_sort_order; + if($_REQUEST['sorder']) $sortorder = $this->db->sql_escape_string($_REQUEST['sorder']); + else if($_SESSION[$currentModule.'_Sort_Order']) + $sortorder = $_SESSION[$currentModule.'_Sort_Order']; + + return $sortorder; + } + + function getOrderBy() { + global $currentModule; + + $orderby = $this->default_order_by; + if($_REQUEST['order_by']) $orderby = $this->db->sql_escape_string($_REQUEST['order_by']); + else if($_SESSION[$currentModule.'_Order_By']) + $orderby = $_SESSION[$currentModule.'_Order_By']; + return $orderby; + } + + function save_module($module) { + } + + /** + * Return query to use based on given modulename, fieldname + * Useful to handle specific case handling for Popup + */ + function getQueryByModuleField($module, $fieldname, $srcrecord) { + // $srcrecord could be empty + } + + /** + * Get list view query (send more WHERE clause condition if required) + */ + function getListQuery($module, $usewhere=false) { + $query = "SELECT vtiger_crmentity.*, $this->table_name.*"; + + // Select Custom Field Table Columns if present + if(!empty($this->customFieldTable)) $query .= ", " . $this->customFieldTable[0] . ".* "; + + $query .= " FROM $this->table_name"; + + $query .= " INNER JOIN vtiger_crmentity ON vtiger_crmentity.crmid = $this->table_name.$this->table_index"; + + // Consider custom table join as well. + if(!empty($this->customFieldTable)) { + $query .= " INNER JOIN ".$this->customFieldTable[0]." ON ".$this->customFieldTable[0].'.'.$this->customFieldTable[1] . + " = $this->table_name.$this->table_index"; + } + $query .= " LEFT JOIN vtiger_users ON vtiger_users.id = vtiger_crmentity.smownerid"; + + if(!empty($this->groupTable)) { + $query .= " + LEFT JOIN " . $this->groupTable[0] . " ON " . $this->groupTable[0].'.'.$this->groupTable[1] . " = $this->table_name.$this->table_index + LEFT JOIN vtiger_groups ON vtiger_groups.groupname = " . $this->groupTable[0] . '.groupname'; + } + $query .= " WHERE vtiger_crmentity.deleted = 0"; + $query .= $this->getListViewSecurityParameter($module); + if($usewhere) { + $query .= " $usewhere "; + } + return $query; + } + + /** + * Apply security restriction (sharing privilege) query part for List view. + */ + function getListViewSecurityParameter($module) { + global $current_user; + require('user_privileges/user_privileges_'.$current_user->id.'.php'); + require('user_privileges/sharing_privileges_'.$current_user->id.'.php'); + + $sec_query = ''; + $tabid = getTabid($module); + + if($is_admin==false && $profileGlobalPermission[1] == 1 && $profileGlobalPermission[2] == 1 + && $defaultOrgSharingPermission[$tabid] == 3) { + + $sec_query .= " AND (vtiger_crmentity.smownerid in($current_user->id) OR vtiger_crmentity.smownerid IN + ( + SELECT vtiger_user2role.userid FROM vtiger_user2role + INNER JOIN vtiger_users ON vtiger_users.id=vtiger_user2role.userid + INNER JOIN vtiger_role ON vtiger_role.roleid=vtiger_user2role.roleid + WHERE vtiger_role.parentrole LIKE '".$current_user_parent_role_seq."::%' + ) + OR vtiger_crmentity.smownerid IN + ( + SELECT shareduserid FROM vtiger_tmp_read_user_sharing_per + WHERE userid=".$current_user->id." AND tabid=".$tabid." + ) + OR + ( + vtiger_crmentity.smownerid in (0)"; + + if(!empty($this->groupTable)) { + $sec_query .= " AND + ("; + + // Build the query based on the group association of current user. + if(sizeof($current_user_groups) > 0) { + $sec_query .= " vtiger_groups.groupid IN (". implode(",", $current_user_groups) .") OR "; + } + $sec_query .= " vtiger_groups.groupid IN + ( + SELECT vtiger_tmp_read_group_sharing_per.sharedgroupid + FROM vtiger_tmp_read_group_sharing_per + WHERE userid=".$current_user->id." and tabid=".$tabid." + )"; + $sec_query .= ") "; + } + + $sec_query .= ") + )"; + } + return $sec_query; + } + + /** + * Create query to export the records. + */ + function create_export_query($where) + { + global $current_user; + $thismodule = $_REQUEST['module']; + + include("include/utils/ExportUtils.php"); + + //To get the Permitted fields query and the permitted fields list + $sql = getPermittedFieldsQuery($thismodule, "detail_view"); + + $fields_list = getFieldsListFromQuery($sql); + + $query = "SELECT $fields_list, ". $this->groupTable[0].'.'.$this->groupTable[1] ." as 'Assigned To Group', + CASE WHEN (vtiger_users.user_name NOT LIKE '') THEN vtiger_users.user_name ELSE vtiger_groups.groupname END + AS user_name FROM vtiger_crmentity INNER JOIN $this->table_name ON vtiger_crmentity.crmid=$this->table_name.$this->table_index"; + + if(!empty($this->customFieldTable)) { + $query .= " INNER JOIN ".$this->customFieldTable[0]." ON ".$this->customFieldTable[0].'.'.$this->customFieldTable[1] . + " = $this->table_name.$this->table_index"; + } + + $query .= " + LEFT JOIN " . $this->groupTable[0] . " ON " . $this->groupTable[0].'.'.$this->groupTable[1] . " = $this->table_name.$this->table_index + LEFT JOIN vtiger_groups ON vtiger_groups.groupname = " . $this->groupTable[0] . '.groupname'; + $query .= " LEFT JOIN vtiger_users ON vtiger_crmentity.smownerid = vtiger_users.id and vtiger_users.status='Active'"; + + $where_auto = " vtiger_crmentity.deleted=0"; + + if($where != '') $query .= " WHERE ($where) AND $where_auto"; + else $query .= " WHERE $where_auto"; + + require('user_privileges/user_privileges_'.$current_user->id.'.php'); + require('user_privileges/sharing_privileges_'.$current_user->id.'.php'); + + // Security Check for Field Access + if($is_admin==false && $profileGlobalPermission[1] == 1 && $profileGlobalPermission[2] == 1 && $defaultOrgSharingPermission[7] == 3) + { + //Added security check to get the permitted records only + $query = $query." ".getListViewSecurityParameter($thismodule); + } + return $query; + } + + /** + * Initialize this instance for importing. + */ + function initImport($module) { + $this->db = new PearDatabase(); + $this->initImportableFields($module); + } + + /** + * Create list query to be shown at the last step of the import. + * Called From: modules/Import/UserLastImport.php + */ + function create_import_query($module) { + global $current_user; + $query = "SELECT vtiger_crmentity.crmid, vtiger_users.user_name, $this->table_name.* FROM $this->table_name + INNER JOIN vtiger_crmentity ON vtiger_crmentity.crmid = $this->table_name.$this->table_index + LEFT JOIN vtiger_users_last_import ON vtiger_users_last_import.bean_id=vtiger_crmentity.crmid + LEFT JOIN vtiger_users ON vtiger_users.id = vtiger_crmentity.smownerid + WHERE vtiger_users_last_import.assigned_user_id='$current_user->id' + AND vtiger_users_last_import.bean_type='$module' + AND vtiger_users_last_import.deleted=0 + AND vtiger_users.status = 'Active'"; + return $query; + } + + /** + * Delete the last imported records. + */ + function undo_import($module, $user_id) { + global $adb; + $count = 0; + $query1 = "select bean_id from vtiger_users_last_import where assigned_user_id=? AND bean_type='$module' AND deleted=0"; + $result1 = $adb->pquery($query1, array($user_id)) or die("Error getting last import for undo: ".mysql_error()); + while ( $row1 = $adb->fetchByAssoc($result1)) + { + $query2 = "update vtiger_crmentity set deleted=1 where crmid=?"; + $result2 = $adb->pquery($query2, array($row1['bean_id'])) or die("Error undoing last import: ".mysql_error()); + $count++; + } + return $count; + } + + /** + * Transform the value while exporting (if required) + */ + function transform_export_value($key, $value) { + return parent::transform_export_value($key, $value); + } + + /** + * Function which will set the assigned user id for import record. + */ + function set_import_assigned_user() + { + global $current_user, $adb; + $record_user = $this->column_fields["assigned_user_id"]; + + if($record_user != $current_user->id){ + $sqlresult = $adb->pquery("select id from vtiger_users where id = ?", array($record_user)); + if($this->db->num_rows($sqlresult)!= 1) { + $this->column_fields["assigned_user_id"] = $current_user->id; + } else { + $row = $adb->fetchByAssoc($sqlresult, -1, false); + if (isset($row['id']) && $row['id'] != -1) { + $this->column_fields["assigned_user_id"] = $row['id']; + } else { + $this->column_fields["assigned_user_id"] = $current_user->id; + } + } + } + } + + /** + * Invoked when special actions are performed on the module. + * @param String Module name + * @param String Event Type (module.postinstall, module.disabled, module.enabled, module.preuninstall) + */ + function vtlib_handler($modulename, $event_type) { + if($event_type == 'module.postinstall') { + // TODO Handle post installation actions + } else if($event_type == 'module.disabled') { + // TODO Handle actions when this module is disabled. + } else if($event_type == 'module.enabled') { + // TODO Handle actions when this module is enabled. + } else if($event_type == 'module.preuninstall') { + // TODO Handle actions when this module is about to be deleted. + } else if($event_type == 'module.preupdate') { + // TODO Handle actions before this module is updated. + } else if($event_type == 'module.postupdate') { + // TODO Handle actions after this module is updated. + } + } + + /** + * Handle saving related module information. + * NOTE: This function has been added to CRMEntity (base class). + * You can override the behavior by re-defining it here. + */ + // function save_related_module($module, $crmid, $with_module, $with_crmid) { } + + /** + * Handle deleting related module information. + * NOTE: This function has been added to CRMEntity (base class). + * You can override the behavior by re-defining it here. + */ + //function delete_related_module($module, $crmid, $with_module, $with_crmid) { } + + /** + * Handle getting related list information. + * NOTE: This function has been added to CRMEntity (base class). + * You can override the behavior by re-defining it here. + */ + //function get_related_list($id, $cur_tab_id, $rel_tab_id, $actions=false) { } +} +?> \ No newline at end of file diff --git a/oss/vtiger/trunk/vtlib/ModuleDir/5.0.4/ModuleFileAjax.php b/oss/vtiger/trunk/vtlib/ModuleDir/5.0.4/ModuleFileAjax.php new file mode 100644 index 00000000..efae0a94 --- /dev/null +++ b/oss/vtiger/trunk/vtlib/ModuleDir/5.0.4/ModuleFileAjax.php @@ -0,0 +1,11 @@ + diff --git a/oss/vtiger/trunk/vtlib/ModuleDir/5.0.4/Popup.php b/oss/vtiger/trunk/vtlib/ModuleDir/5.0.4/Popup.php new file mode 100644 index 00000000..40aae3fa --- /dev/null +++ b/oss/vtiger/trunk/vtlib/ModuleDir/5.0.4/Popup.php @@ -0,0 +1,11 @@ + diff --git a/oss/vtiger/trunk/vtlib/ModuleDir/5.0.4/QuickCreate.php b/oss/vtiger/trunk/vtlib/ModuleDir/5.0.4/QuickCreate.php new file mode 100644 index 00000000..78fe10f6 --- /dev/null +++ b/oss/vtiger/trunk/vtlib/ModuleDir/5.0.4/QuickCreate.php @@ -0,0 +1,11 @@ + diff --git a/oss/vtiger/trunk/vtlib/ModuleDir/5.0.4/Save.php b/oss/vtiger/trunk/vtlib/ModuleDir/5.0.4/Save.php new file mode 100644 index 00000000..d0495681 --- /dev/null +++ b/oss/vtiger/trunk/vtlib/ModuleDir/5.0.4/Save.php @@ -0,0 +1,35 @@ +mode = $mode; +if($record)$focus->id = $record; + +$focus->save($currentModule); +$return_id = $focus->id; + +if($_REQUEST['parenttab'] != '') $parenttab = $_REQUEST['parenttab']; +if($_REQUEST['return_module'] != '') $return_module = $_REQUEST['return_module']; +else $return_module = $currentModule; + +if($_REQUEST['return_action'] != '') $return_action = $_REQUEST['return_action']; +else $return_action = "DetailView"; + +if($_REQUEST['return_id'] != '') $return_id = $_REQUEST['return_id']; + +header("Location: index.php?action=$return_action&module=$return_module&record=$return_id&parenttab=$parenttab&start=".$_REQUEST['pagenumber'].$search); + +?> \ No newline at end of file diff --git a/oss/vtiger/trunk/vtlib/ModuleDir/5.0.4/TagCloud.php b/oss/vtiger/trunk/vtlib/ModuleDir/5.0.4/TagCloud.php new file mode 100644 index 00000000..8343cd5b --- /dev/null +++ b/oss/vtiger/trunk/vtlib/ModuleDir/5.0.4/TagCloud.php @@ -0,0 +1,11 @@ + diff --git a/oss/vtiger/trunk/vtlib/ModuleDir/5.0.4/index.php b/oss/vtiger/trunk/vtlib/ModuleDir/5.0.4/index.php new file mode 100644 index 00000000..8dbd1b44 --- /dev/null +++ b/oss/vtiger/trunk/vtlib/ModuleDir/5.0.4/index.php @@ -0,0 +1,13 @@ + diff --git a/oss/vtiger/trunk/vtlib/ModuleDir/5.0.4/language/en_us.lang.php b/oss/vtiger/trunk/vtlib/ModuleDir/5.0.4/language/en_us.lang.php new file mode 100644 index 00000000..de2b1c78 --- /dev/null +++ b/oss/vtiger/trunk/vtlib/ModuleDir/5.0.4/language/en_us.lang.php @@ -0,0 +1,19 @@ + 'Module Name', + + 'LBL_CUSTOM_INFORMATION' => 'Custom Information', + 'LBL_MODULEBLOCK_INFORMATION' => 'ModuleBlock Information', + + 'ModuleFieldLabel' => 'ModuleFieldLabel Text', +); + +?> diff --git a/oss/vtiger/trunk/vtlib/ModuleDir/5.0.4/updateRelations.php b/oss/vtiger/trunk/vtlib/ModuleDir/5.0.4/updateRelations.php new file mode 100644 index 00000000..8e66b88f --- /dev/null +++ b/oss/vtiger/trunk/vtlib/ModuleDir/5.0.4/updateRelations.php @@ -0,0 +1,58 @@ +delete_related_module($currentModule, $forCRMRecord, $destinationModule, $ids); + } + if($singlepane_view == 'true') { + header("Location: index.php?module=$currentModule&record=$forCRMRecord&action=DetailView&parenttab=$parenttab"); + } else { + header("Location: index.php?module=$currentModule&record=$forCRMRecord&action=CallRelatedList&parenttab=$parenttab"); + } + exit; +} + +if(!empty($_REQUEST['idlist'])) { + $ids = explode (";",trim($idlist,";")); + if(function_exists('checkFileAccess')) { + checkFileAccess("modules/$currentModule/$currentModule.php"); + } + require_once("modules/$currentModule/$currentModule.php"); + $focus = new $currentModule(); + if(method_exists($focus, 'save_related_module')) { + $focus->save_related_module($currentModule, $forCRMRecord, $destinationModule, $ids); + } + if($singlepane_view == 'true') { + header("Location: index.php?module=$currentModule&record=$forCRMRecord&action=DetailView&parenttab=$parenttab"); + } else { + header("Location: index.php?module=$currentModule&record=$forCRMRecord&action=CallRelatedList&parenttab=$parenttab"); + } +} else if(!empty($_REQUEST['entityid'])){ + // TODO: Handle this case +} +?> diff --git a/oss/vtiger/trunk/vtlib/ModuleDir/5.1.0/CallRelatedList.php b/oss/vtiger/trunk/vtlib/ModuleDir/5.1.0/CallRelatedList.php new file mode 100644 index 00000000..99733f53 --- /dev/null +++ b/oss/vtiger/trunk/vtlib/ModuleDir/5.1.0/CallRelatedList.php @@ -0,0 +1,71 @@ +retrieve_entity_info($record, $currentModule); + $focus->id = $record; + } + + $smarty = new vtigerCRM_Smarty; + + if($isduplicate == 'true') $focus->id = ''; + if(isset($_REQUEST['mode']) && $_REQUEST['mode'] != ' ') $smarty->assign("OP_MODE",vtlib_purify($_REQUEST['mode'])); + if(!$_SESSION['rlvs'][$currentModule]) unset($_SESSION['rlvs']); + + // Identify this module as custom module. + $smarty->assign('CUSTOM_MODULE', true); + + $smarty->assign('APP', $app_strings); + $smarty->assign('MOD', $mod_strings); + $smarty->assign('MODULE', $currentModule); + // TODO: Update Single Module Instance name here. + $smarty->assign('SINGLE_MOD', getTranslatedString($currentModule)); + $smarty->assign('CATEGORY', $category); + $smarty->assign('IMAGE_PATH', "themes/$theme/images/"); + $smarty->assign('THEME', $theme); + $smarty->assign('ID', $focus->id); + $smarty->assign('MODE', $focus->mode); + $smarty->assign('CHECK', $tool_buttons); + + $smarty->assign('NAME', $focus->column_fields[$focus->def_detailview_recname]); + $smarty->assign('UPDATEINFO',updateInfo($focus->id)); + + // Module Sequence Numbering + $mod_seq_field = getModuleSequenceField($currentModule); + if ($mod_seq_field != null) { + $mod_seq_id = $focus->column_fields[$mod_seq_field['name']]; + } else { + $mod_seq_id = $focus->id; + } + $smarty->assign('MOD_SEQ_ID', $mod_seq_id); + // END + + $related_array = getRelatedLists($currentModule, $focus); + + $smarty->assign('RELATEDLISTS', $related_array); + $smarty->display('RelatedLists.tpl'); +} +?> \ No newline at end of file diff --git a/oss/vtiger/trunk/vtlib/ModuleDir/5.1.0/CustomView.php b/oss/vtiger/trunk/vtlib/ModuleDir/5.1.0/CustomView.php new file mode 100644 index 00000000..aebb8b53 --- /dev/null +++ b/oss/vtiger/trunk/vtlib/ModuleDir/5.1.0/CustomView.php @@ -0,0 +1,12 @@ + diff --git a/oss/vtiger/trunk/vtlib/ModuleDir/5.1.0/Delete.php b/oss/vtiger/trunk/vtlib/ModuleDir/5.1.0/Delete.php new file mode 100644 index 00000000..c37c3c1b --- /dev/null +++ b/oss/vtiger/trunk/vtlib/ModuleDir/5.1.0/Delete.php @@ -0,0 +1,27 @@ + \ No newline at end of file diff --git a/oss/vtiger/trunk/vtlib/ModuleDir/5.1.0/DetailView.php b/oss/vtiger/trunk/vtlib/ModuleDir/5.1.0/DetailView.php new file mode 100644 index 00000000..daa4d321 --- /dev/null +++ b/oss/vtiger/trunk/vtlib/ModuleDir/5.1.0/DetailView.php @@ -0,0 +1,102 @@ +id = $record; + $focus->retrieve_entity_info($record, $currentModule); +} +if($isduplicate == 'true') $focus->id = ''; + +// Identify this module as custom module. +$smarty->assign('CUSTOM_MODULE', true); + +$smarty->assign('APP', $app_strings); +$smarty->assign('MOD', $mod_strings); +$smarty->assign('MODULE', $currentModule); +// TODO: Update Single Module Instance name here. +$smarty->assign('SINGLE_MOD', 'SINGLE_'.$currentModule); +$smarty->assign('CATEGORY', $category); +$smarty->assign('IMAGE_PATH', "themes/$theme/images/"); +$smarty->assign('THEME', $theme); +$smarty->assign('ID', $focus->id); +$smarty->assign('MODE', $focus->mode); + +$recordName = array_values(getEntityName($currentModule, $focus->id)); +$recordName = $recordName[0]; +$smarty->assign('NAME', $recordName); +$smarty->assign('UPDATEINFO',updateInfo($focus->id)); + +// Module Sequence Numbering +$mod_seq_field = getModuleSequenceField($currentModule); +if ($mod_seq_field != null) { + $mod_seq_id = $focus->column_fields[$mod_seq_field['name']]; +} else { + $mod_seq_id = $focus->id; +} +$smarty->assign('MOD_SEQ_ID', $mod_seq_id); +// END + +$validationArray = split_validationdataArray(getDBValidationData($focus->tab_name, $tabid)); +$smarty->assign('VALIDATION_DATA_FIELDNAME',$validationArray['fieldname']); +$smarty->assign('VALIDATION_DATA_FIELDDATATYPE',$validationArray['datatype']); +$smarty->assign('VALIDATION_DATA_FIELDLABEL',$validationArray['fieldlabel']); + +$smarty->assign('EDIT_PERMISSION', isPermitted($currentModule, 'EditView', $record)); +$smarty->assign('CHECK', $tool_buttons); + +if(PerformancePrefs::getBoolean('DETAILVIEW_RECORD_NAVIGATION', true) && isset($_SESSION[$currentModule.'_listquery'])){ + $recordNavigationInfo = ListViewSession::getListViewNavigation($focus->id); + VT_detailViewNavigation($smarty,$recordNavigationInfo,$focus->id); +} + +$smarty->assign('IS_REL_LIST', isPresentRelatedLists($currentModule)); +$smarty->assign('SinglePane_View', $singlepane_view); + +if($singlepane_view == 'true') { + $related_array = getRelatedLists($currentModule,$focus); + $smarty->assign("RELATEDLISTS", $related_array); +} + +if(isPermitted($currentModule, 'EditView', $record) == 'yes') + $smarty->assign('EDIT_DUPLICATE', 'permitted'); +if(isPermitted($currentModule, 'Delete', $record) == 'yes') + $smarty->assign('DELETE', 'permitted'); + +$smarty->assign('BLOCKS', getBlocks($currentModule,'detail_view','',$focus->column_fields)); + +// Gather the custom link information to display +include_once('vtlib/Vtiger/Link.php'); +$customlink_params = Array('MODULE'=>$currentModule, 'RECORD'=>$focus->id, 'ACTION'=>vtlib_purify($_REQUEST['action'])); +$smarty->assign('CUSTOM_LINKS', Vtiger_Link::getAllByType(getTabid($currentModule), Array('DETAILVIEWBASIC','DETAILVIEW'), $customlink_params)); +// END + +// Record Change Notification +$focus->markAsViewed($current_user->id); +// END + +$smarty->assign('DETAILVIEW_AJAX_EDIT', PerformancePrefs::getBoolean('DETAILVIEW_AJAX_EDIT', true)); + +$smarty->display('DetailView.tpl'); + +?> \ No newline at end of file diff --git a/oss/vtiger/trunk/vtlib/ModuleDir/5.1.0/DetailViewAjax.php b/oss/vtiger/trunk/vtlib/ModuleDir/5.1.0/DetailViewAjax.php new file mode 100644 index 00000000..43da8072 --- /dev/null +++ b/oss/vtiger/trunk/vtlib/ModuleDir/5.1.0/DetailViewAjax.php @@ -0,0 +1,39 @@ +retrieve_entity_info($crmid, $currentModule); + $modObj->column_fields[$fieldname] = $fieldvalue; + $modObj->id = $crmid; + $modObj->mode = 'edit'; + $modObj->save($currentModule); + if($modObj->id != '') + { + echo ':#:SUCCESS'; + }else + { + echo ':#:FAILURE'; + } + }else + { + echo ':#:FAILURE'; + } +} +?> \ No newline at end of file diff --git a/oss/vtiger/trunk/vtlib/ModuleDir/5.1.0/EditView.php b/oss/vtiger/trunk/vtlib/ModuleDir/5.1.0/EditView.php new file mode 100644 index 00000000..3c03d614 --- /dev/null +++ b/oss/vtiger/trunk/vtlib/ModuleDir/5.1.0/EditView.php @@ -0,0 +1,113 @@ +assign("SEARCH", $searchurl); +//4600 ends + +if($record) { + $focus->id = $record; + $focus->mode = 'edit'; + $focus->retrieve_entity_info($record, $currentModule); +} +if($isduplicate == 'true') { + $focus->id = ''; + $focus->mode = ''; +} +if(empty($_REQUEST['record']) && $focus->mode != 'edit'){ + setObjectValuesFromRequest($focus); +} + +$disp_view = getView($focus->mode); +if($disp_view == 'edit_view') + $smarty->assign('BLOCKS', getBlocks($currentModule, $disp_view, $focus->mode, $focus->column_fields)); +else + $smarty->assign('BASBLOCKS', getBlocks($currentModule, $disp_view, $focus->mode, $focus->column_fields, 'BAS')); + +$smarty->assign('OP_MODE',$disp_view); +$smarty->assign('APP', $app_strings); +$smarty->assign('MOD', $mod_strings); +$smarty->assign('MODULE', $currentModule); +// TODO: Update Single Module Instance name here. +$smarty->assign('SINGLE_MOD', getTranslatedString('SINGLE_'.$currentModule)); +$smarty->assign('CATEGORY', $category); +$smarty->assign("THEME", $theme); +$smarty->assign('IMAGE_PATH', "themes/$theme/images/"); +$smarty->assign('ID', $focus->id); +$smarty->assign('MODE', $focus->mode); + +$smarty->assign('CHECK', Button_Check($currentModule)); +$smarty->assign('DUPLICATE', $isduplicate); + +if($focus->mode == 'edit' || $isduplicate) { + $recordName = array_values(getEntityName($currentModule, $record)); + $recordName = $recordName[0]; + $smarty->assign('NAME', $recordName); + $smarty->assign('UPDATEINFO',updateInfo($record)); +} + +if(isset($_REQUEST['return_module'])) $smarty->assign("RETURN_MODULE", vtlib_purify($_REQUEST['return_module'])); +if(isset($_REQUEST['return_action'])) $smarty->assign("RETURN_ACTION", vtlib_purify($_REQUEST['return_action'])); +if(isset($_REQUEST['return_id'])) $smarty->assign("RETURN_ID", vtlib_purify($_REQUEST['return_id'])); +if (isset($_REQUEST['return_viewname'])) $smarty->assign("RETURN_VIEWNAME", vtlib_purify($_REQUEST['return_viewname'])); + +// Field Validation Information +$tabid = getTabid($currentModule); +$validationData = getDBValidationData($focus->tab_name,$tabid); +$validationArray = split_validationdataArray($validationData); + +$smarty->assign("VALIDATION_DATA_FIELDNAME",$validationArray['fieldname']); +$smarty->assign("VALIDATION_DATA_FIELDDATATYPE",$validationArray['datatype']); +$smarty->assign("VALIDATION_DATA_FIELDLABEL",$validationArray['fieldlabel']); + +// In case you have a date field +$smarty->assign("CALENDAR_LANG", $app_strings['LBL_JSCALENDAR_LANG']); + +global $adb; +// Module Sequence Numbering +$mod_seq_field = getModuleSequenceField($currentModule); +if($focus->mode != 'edit' && $mod_seq_field != null) { + $autostr = getTranslatedString('MSG_AUTO_GEN_ON_SAVE'); + $mod_seq_string = $adb->pquery("SELECT prefix, cur_id from vtiger_modentity_num where semodule = ? and active=1",array($currentModule)); + $mod_seq_prefix = $adb->query_result($mod_seq_string,0,'prefix'); + $mod_seq_no = $adb->query_result($mod_seq_string,0,'cur_id'); + if($adb->num_rows($mod_seq_string) == 0 || $focus->checkModuleSeqNumber($focus->table_name, $mod_seq_field['column'], $mod_seq_prefix.$mod_seq_no)) + echo '
'. getTranslatedString('LBL_DUPLICATE'). ' '. getTranslatedString($mod_seq_field['label']) + .' - '. getTranslatedString('LBL_CLICK') .' '.getTranslatedString('LBL_HERE').' ' + . getTranslatedString('LBL_TO_CONFIGURE'). ' '. getTranslatedString($mod_seq_field['label']) .''; + else + $smarty->assign("MOD_SEQ_ID",$autostr); +} else { + $smarty->assign("MOD_SEQ_ID", $focus->column_fields[$mod_seq_field['name']]); +} +// END + +// Gather the help information associated with fields +$smarty->assign('FIELDHELPINFO', vtlib_getFieldHelpInfo($currentModule)); +// END + +if($focus->mode == 'edit') { + $smarty->display('salesEditView.tpl'); +} else { + $smarty->display('CreateView.tpl'); +} + +?> \ No newline at end of file diff --git a/oss/vtiger/trunk/vtlib/ModuleDir/5.1.0/ExportRecords.php b/oss/vtiger/trunk/vtlib/ModuleDir/5.1.0/ExportRecords.php new file mode 100644 index 00000000..31029bc0 --- /dev/null +++ b/oss/vtiger/trunk/vtlib/ModuleDir/5.1.0/ExportRecords.php @@ -0,0 +1,12 @@ + diff --git a/oss/vtiger/trunk/vtlib/ModuleDir/5.1.0/FindDuplicateRecords.php b/oss/vtiger/trunk/vtlib/ModuleDir/5.1.0/FindDuplicateRecords.php new file mode 100644 index 00000000..b1a36b7b --- /dev/null +++ b/oss/vtiger/trunk/vtlib/ModuleDir/5.1.0/FindDuplicateRecords.php @@ -0,0 +1,106 @@ +pquery($sql, array($id)); + DeleteEntity($req_module,$return_module,$focus,$id,""); + } + else { + $ids_list[] = $id; + } +} + if(count($ids_list) > 0) { + $ret = getEntityName($req_module,$ids_list); + if(count($ret) > 0) + { + $errormsg = implode(',',$ret); + } + echo "
"; + echo "
+ + + + + + + + + +
+ $app_strings[LBL_DUP_PERMISSION] $req_module $errormsg
+ $app_strings[LBL_GO_BACK]
+
+
"; + echo "
"; + exit; + } +} + +include("include/saveMergeCriteria.php"); +$ret_arr=getDuplicateRecordsArr($req_module); + +$fld_values=$ret_arr[0]; +$total_num_group=count($fld_values); +$fld_name=$ret_arr[1]; +$ui_type=$ret_arr[2]; + +$smarty->assign("NAVIGATION",$ret_arr["navigation"]);//Added for page navigation +$smarty->assign("MODULE",$req_module); +$smarty->assign("NUM_GROUP",$total_num_group); +$smarty->assign("FIELD_NAMES",$fld_name); +$smarty->assign("CATEGORY",$parenttab); +$smarty->assign("ALL_VALUES",$fld_values); +if(isPermitted($req_module,'Delete','') == 'yes') + $button_del = $app_strings['LBL_MASS_DELETE']; +$smarty->assign("DELETE",$button_del); + +$smarty->assign("MOD", return_module_language($current_language,$req_module)); +$smarty->assign("THEME", $theme); +$smarty->assign("IMAGE_PATH",$image_path); +$smarty->assign("APP", $app_strings); +$smarty->assign("CMOD", $mod_strings); +$smarty->assign("MODE",'view'); +if(isset($_REQUEST['button_view'])) +{ + $smarty->assign("VIEW",'true'); +} +if(isset($_REQUEST['ajax']) && $_REQUEST['ajax'] != '') + $smarty->display("FindDuplicateAjax.tpl"); +else + $smarty->display('FindDuplicateDisplay.tpl'); + +?> \ No newline at end of file diff --git a/oss/vtiger/trunk/vtlib/ModuleDir/5.1.0/Import.php b/oss/vtiger/trunk/vtlib/ModuleDir/5.1.0/Import.php new file mode 100644 index 00000000..576068f5 --- /dev/null +++ b/oss/vtiger/trunk/vtlib/ModuleDir/5.1.0/Import.php @@ -0,0 +1,12 @@ + diff --git a/oss/vtiger/trunk/vtlib/ModuleDir/5.1.0/ListView.php b/oss/vtiger/trunk/vtlib/ModuleDir/5.1.0/ListView.php new file mode 100644 index 00000000..368ea4da --- /dev/null +++ b/oss/vtiger/trunk/vtlib/ModuleDir/5.1.0/ListView.php @@ -0,0 +1,190 @@ +initSortbyField($currentModule); +$sorder = $focus->getSortOrder(); +$order_by = $focus->getOrderBy(); + +$_SESSION[$currentModule."_Order_by"] = $order_by; +$_SESSION[$currentModule."_Sort_Order"]=$sorder; + +$smarty = new vtigerCRM_Smarty(); + +// Identify this module as custom module. +$smarty->assign('CUSTOM_MODULE', true); + +$smarty->assign('MOD', $mod_strings); +$smarty->assign('APP', $app_strings); +$smarty->assign('MODULE', $currentModule); +$smarty->assign('SINGLE_MOD', getTranslatedString('SINGLE_'.$currentModule)); +$smarty->assign('CATEGORY', $category); +$smarty->assign('BUTTONS', $list_buttons); +$smarty->assign('CHECK', $tool_buttons); +$smarty->assign('THEME', $theme); +$smarty->assign('IMAGE_PATH', "themes/$theme/images/"); + +$smarty->assign('CHANGE_OWNER', getUserslist()); +$smarty->assign('CHANGE_GROUP_OWNER', getGroupslist()); + +// Enabling Module Search +$url_string = ''; +if($_REQUEST['query'] == 'true') { + list($where, $ustring) = split('#@@#', getWhereCondition($currentModule)); + $url_string .= "&query=true$ustring"; + $smarty->assign('SEARCH_URL', $url_string); +} + +// Custom View +$customView = new CustomView($currentModule); +$viewid = $customView->getViewId($currentModule); +$customview_html = $customView->getCustomViewCombo($viewid); +$viewinfo = $customView->getCustomViewByCvid($viewid); + +// Feature available from 5.1 +if(method_exists($customView, 'isPermittedChangeStatus')) { + // Approving or Denying status-public by the admin in CustomView + $statusdetails = $customView->isPermittedChangeStatus($viewinfo['status']); + + // To check if a user is able to edit/delete a CustomView + $edit_permit = $customView->isPermittedCustomView($viewid,'EditView',$currentModule); + $delete_permit = $customView->isPermittedCustomView($viewid,'Delete',$currentModule); + + $smarty->assign("CUSTOMVIEW_PERMISSION",$statusdetails); + $smarty->assign("CV_EDIT_PERMIT",$edit_permit); + $smarty->assign("CV_DELETE_PERMIT",$delete_permit); +} +// END + +$smarty->assign("VIEWID", $viewid); + +if($viewinfo['viewname'] == 'All') $smarty->assign('ALL', 'All'); + +if($viewid ==0) +{ + echo "
"; + echo "
+ + + + + + + + + +
$app_strings[LBL_PERMISSION]
+ $app_strings[LBL_GO_BACK]
+
+
"; + echo "
"; + exit; +} + +$listquery = getListQuery($currentModule); +$list_query= $customView->getModifiedCvListQuery($viewid, $listquery, $currentModule); + +if($where != '') { + $list_query = "$list_query AND $where"; +} + +// Sorting +if(!empty($order_by)) { + if($order_by == 'smownerid') $list_query .= ' ORDER BY user_name '.$sorder; + else { + $tablename = getTableNameForField($currentModule, $order_by); + $tablename = ($tablename != '')? ($tablename . '.') : ''; + $list_query .= ' ORDER BY ' . $tablename . $order_by . ' ' . $sorder; + } +} + +//Postgres 8 fixes +if( $adb->dbType == "pgsql") + $list_query = fixPostgresQuery( $list_query, $log, 0); + +if(PerformancePrefs::getBoolean('LISTVIEW_COMPUTE_PAGE_COUNT', false) === true){ + $count_result = $adb->query( mkCountQuery( $list_query)); + $noofrows = $adb->query_result($count_result,0,"count"); +}else{ + $noofrows = null; +} + +$queryMode = (isset($_REQUEST['query']) && $_REQUEST['query'] == 'true'); +$start = ListViewSession::getRequestCurrentPage($currentModule, $list_query, $viewid, $queryMode); + +$navigation_array = VT_getSimpleNavigationValues($start,$list_max_entries_per_page,$noofrows); + +$limit_start_rec = ($start-1) * $list_max_entries_per_page; + +if( $adb->dbType == "pgsql") + $list_result = $adb->pquery($list_query. " OFFSET $limit_start_rec LIMIT $list_max_entries_per_page", array()); +else + $list_result = $adb->pquery($list_query. " LIMIT $limit_start_rec, $list_max_entries_per_page", array()); + +$recordListRangeMsg = getRecordRangeMessage($list_result, $limit_start_rec); +$smarty->assign('recordListRange',$recordListRangeMsg); + +$smarty->assign("CUSTOMVIEW_OPTION",$customview_html); + +// Navigation +$navigationOutput = getTableHeaderSimpleNavigation($navigation_array, $url_string, $currentModule, 'index', $viewid); +$smarty->assign("NAVIGATION", $navigationOutput); + +$listview_header = getListViewHeader($focus,$currentModule,$url_string,$sorder,$order_by,'',$customView); +$listview_entries = getListViewEntries($focus,$currentModule,$list_result,$navigation_array,'','','EditView','Delete',$customView); +$listview_header_search = getSearchListHeaderValues($focus,$currentModule,$url_string,$sorder,$order_by,'',$customView); + +$smarty->assign('LISTHEADER', $listview_header); +$smarty->assign('LISTENTITY', $listview_entries); +$smarty->assign('SEARCHLISTHEADER',$listview_header_search); + +// Module Search +$alphabetical = AlphabeticalSearch($currentModule,'index',$focus->def_basicsearch_col,'true','basic','','','','',$viewid); +$fieldnames = getAdvSearchfields($currentModule); +$criteria = getcriteria_options(); +$smarty->assign("ALPHABETICAL", $alphabetical); +$smarty->assign("FIELDNAMES", $fieldnames); +$smarty->assign("CRITERIA", $criteria); + +$smarty->assign("AVALABLE_FIELDS", getMergeFields($currentModule,"available_fields")); +$smarty->assign("FIELDS_TO_MERGE", getMergeFields($currentModule,"fileds_to_merge")); + +$_SESSION[$currentModule.'_listquery'] = $list_query; + +if(isset($_REQUEST['ajax']) && $_REQUEST['ajax'] != '') + $smarty->display("ListViewEntries.tpl"); +else + $smarty->display('ListView.tpl'); + +?> \ No newline at end of file diff --git a/oss/vtiger/trunk/vtlib/ModuleDir/5.1.0/ListViewPagging.php b/oss/vtiger/trunk/vtlib/ModuleDir/5.1.0/ListViewPagging.php new file mode 100644 index 00000000..333f1768 --- /dev/null +++ b/oss/vtiger/trunk/vtlib/ModuleDir/5.1.0/ListViewPagging.php @@ -0,0 +1,11 @@ + \ No newline at end of file diff --git a/oss/vtiger/trunk/vtlib/ModuleDir/5.1.0/MassEdit.php b/oss/vtiger/trunk/vtlib/ModuleDir/5.1.0/MassEdit.php new file mode 100644 index 00000000..a48f6146 --- /dev/null +++ b/oss/vtiger/trunk/vtlib/ModuleDir/5.1.0/MassEdit.php @@ -0,0 +1,44 @@ +mode = ''; +$mode = 'mass_edit'; + +$disp_view = getView($focus->mode); +$idstring = $_REQUEST['idstring']; + +$smarty = new vtigerCRM_Smarty; +$smarty->assign('MODULE',$currentModule); +$smarty->assign('APP',$app_strings); +$smarty->assign('THEME', $theme); +$smarty->assign('IMAGE_PATH', "themes/$theme/images/"); +$smarty->assign('IDS',$idstring); +$smarty->assign('MASS_EDIT','1'); +$smarty->assign('BLOCKS',getBlocks($currentModule,$disp_view,$mode,$focus->column_fields)); +$smarty->assign("CATEGORY",getParentTab()); + +// Field Validation Information +$tabid = getTabid($currentModule); +$validationData = getDBValidationData($focus->tab_name,$tabid); +$validationArray = split_validationdataArray($validationData); + +$smarty->assign("VALIDATION_DATA_FIELDNAME",$validationArray['fieldname']); +$smarty->assign("VALIDATION_DATA_FIELDDATATYPE",$validationArray['datatype']); +$smarty->assign("VALIDATION_DATA_FIELDLABEL",$validationArray['fieldlabel']); + +$smarty->display('MassEditForm.tpl'); + +?> \ No newline at end of file diff --git a/oss/vtiger/trunk/vtlib/ModuleDir/5.1.0/MassEditSave.php b/oss/vtiger/trunk/vtlib/ModuleDir/5.1.0/MassEditSave.php new file mode 100644 index 00000000..0c1aa37e --- /dev/null +++ b/oss/vtiger/trunk/vtlib/ModuleDir/5.1.0/MassEditSave.php @@ -0,0 +1,65 @@ +retrieve_entity_info($recordid, $currentModule); + $focus->mode = 'edit'; + $focus->id = $recordid; + foreach($focus->column_fields as $fieldname => $val) + { + if(isset($_REQUEST[$fieldname."_mass_edit_check"])) { + if($fieldname == 'assigned_user_id'){ + if($_REQUEST['assigntype'] == 'U') { + $value = $_REQUEST['assigned_user_id']; + } elseif($_REQUEST['assigntype'] == 'T') { + $value = $_REQUEST['assigned_group_id']; + } + } else { + if(is_array($_REQUEST[$fieldname])) + $value = $_REQUEST[$fieldname]; + else + $value = trim($_REQUEST[$fieldname]); + } + $focus->column_fields[$fieldname] = $value; + } + else { + $focus->column_fields[$fieldname] = decode_html($focus->column_fields[$fieldname]); + } + } + $focus->save($currentModule); + } + } +} + +$parenttab = getParentTab(); +header("Location: index.php?module=$return_module&action=$return_action&parenttab=$parenttab$rstart"); +?> \ No newline at end of file diff --git a/oss/vtiger/trunk/vtlib/ModuleDir/5.1.0/ModuleFile.js b/oss/vtiger/trunk/vtlib/ModuleDir/5.1.0/ModuleFile.js new file mode 100644 index 00000000..3fd0758c --- /dev/null +++ b/oss/vtiger/trunk/vtlib/ModuleDir/5.1.0/ModuleFile.js @@ -0,0 +1,8 @@ +/*+********************************************************************************** + * The contents of this file are subject to the vtiger CRM Public License Version 1.0 + * ("License"); You may not use this file except in compliance with the License + * The Original Code is: vtiger CRM Open Source + * The Initial Developer of the Original Code is vtiger. + * Portions created by vtiger are Copyright (C) vtiger. + * All Rights Reserved. + ************************************************************************************/ diff --git a/oss/vtiger/trunk/vtlib/ModuleDir/5.1.0/ModuleFile.php b/oss/vtiger/trunk/vtlib/ModuleDir/5.1.0/ModuleFile.php new file mode 100644 index 00000000..6bd42952 --- /dev/null +++ b/oss/vtiger/trunk/vtlib/ModuleDir/5.1.0/ModuleFile.php @@ -0,0 +1,451 @@ + 'crmid', + 'vtiger_payslip' => 'payslipid', + 'vtiger_payslipcf' => 'payslipid'); + + /** + * Mandatory for Listing (Related listview) + */ + var $list_fields = Array ( + /* Format: Field Label => Array(tablename, columnname) */ + // tablename should not have prefix 'vtiger_' + 'Payslip Name'=> Array('payslip', 'payslipname'), + 'Assigned To' => Array('crmentity','smownerid') + ); + var $list_fields_name = Array( + /* Format: Field Label => fieldname */ + 'Payslip Name'=> 'payslipname', + 'Assigned To' => 'assigned_user_id' + ); + + // Make the field link to detail view from list view (Fieldname) + var $list_link_field = 'payslipname'; + + // For Popup listview and UI type support + var $search_fields = Array( + /* Format: Field Label => Array(tablename, columnname) */ + // tablename should not have prefix 'vtiger_' + 'Payslip Name'=> Array('payslip', 'payslipname') + ); + var $search_fields_name = Array( + /* Format: Field Label => fieldname */ + 'Payslip Name'=> 'payslipname' + ); + + // For Popup window record selection + var $popup_fields = Array('payslipname'); + + // Placeholder for sort fields - All the fields will be initialized for Sorting through initSortFields + var $sortby_fields = Array(); + + // For Alphabetical search + var $def_basicsearch_col = 'payslipname'; + + // Column value to use on detail view record text display + var $def_detailview_recname = 'payslipname'; + + // Required Information for enabling Import feature + var $required_fields = Array('payslipname'=>1); + + // Callback function list during Importing + var $special_functions = Array('set_import_assigned_user'); + + var $default_order_by = 'payslipname'; + var $default_sort_order='ASC'; + // Used when enabling/disabling the mandatory fields for the module. + // Refers to vtiger_field.fieldname values. + var $mandatory_fields = Array('createdtime', 'modifiedtime', 'payslipname'); + + function __construct() { + global $log, $currentModule; + $this->column_fields = getColumnFields($currentModule); + $this->db = PearDatabase::getInstance(); + $this->log = $log; + } + + function getSortOrder() { + global $currentModule; + + $sortorder = $this->default_sort_order; + if($_REQUEST['sorder']) $sortorder = $this->db->sql_escape_string($_REQUEST['sorder']); + else if($_SESSION[$currentModule.'_Sort_Order']) + $sortorder = $_SESSION[$currentModule.'_Sort_Order']; + + return $sortorder; + } + + function getOrderBy() { + global $currentModule; + + $use_default_order_by = ''; + if(PerformancePrefs::getBoolean('LISTVIEW_DEFAULT_SORTING', true)) { + $use_default_order_by = $this->default_order_by; + } + + $orderby = $use_default_order_by; + if($_REQUEST['order_by']) $orderby = $this->db->sql_escape_string($_REQUEST['order_by']); + else if($_SESSION[$currentModule.'_Order_By']) + $orderby = $_SESSION[$currentModule.'_Order_By']; + return $orderby; + } + + function save_module($module) { + } + + /** + * Return query to use based on given modulename, fieldname + * Useful to handle specific case handling for Popup + */ + function getQueryByModuleField($module, $fieldname, $srcrecord) { + // $srcrecord could be empty + } + + /** + * Get list view query (send more WHERE clause condition if required) + */ + function getListQuery($module, $where='') { + $query = "SELECT vtiger_crmentity.*, $this->table_name.*"; + + // Select Custom Field Table Columns if present + if(!empty($this->customFieldTable)) $query .= ", " . $this->customFieldTable[0] . ".* "; + + $query .= " FROM $this->table_name"; + + $query .= " INNER JOIN vtiger_crmentity ON vtiger_crmentity.crmid = $this->table_name.$this->table_index"; + + // Consider custom table join as well. + if(!empty($this->customFieldTable)) { + $query .= " INNER JOIN ".$this->customFieldTable[0]." ON ".$this->customFieldTable[0].'.'.$this->customFieldTable[1] . + " = $this->table_name.$this->table_index"; + } + $query .= " LEFT JOIN vtiger_users ON vtiger_users.id = vtiger_crmentity.smownerid"; + $query .= " LEFT JOIN vtiger_groups ON vtiger_groups.groupid = vtiger_crmentity.smownerid"; + + $linkedModulesQuery = $this->db->pquery("SELECT distinct fieldname, columnname, relmodule FROM vtiger_field" . + " INNER JOIN vtiger_fieldmodulerel ON vtiger_fieldmodulerel.fieldid = vtiger_field.fieldid" . + " WHERE uitype='10' AND vtiger_fieldmodulerel.module=?", array($module)); + $linkedFieldsCount = $this->db->num_rows($linkedModulesQuery); + + for($i=0; $i<$linkedFieldsCount; $i++) { + $related_module = $this->db->query_result($linkedModulesQuery, $i, 'relmodule'); + $fieldname = $this->db->query_result($linkedModulesQuery, $i, 'fieldname'); + $columnname = $this->db->query_result($linkedModulesQuery, $i, 'columnname'); + + $other = CRMEntity::getInstance($related_module); + vtlib_setup_modulevars($related_module, $other); + + $query .= " LEFT JOIN $other->table_name ON $other->table_name.$other->table_index = $this->table_name.$columnname"; + } + + $query .= " WHERE vtiger_crmentity.deleted = 0 ".$where; + $query .= $this->getListViewSecurityParameter($module); + return $query; + } + + /** + * Apply security restriction (sharing privilege) query part for List view. + */ + function getListViewSecurityParameter($module) { + global $current_user; + require('user_privileges/user_privileges_'.$current_user->id.'.php'); + require('user_privileges/sharing_privileges_'.$current_user->id.'.php'); + + $sec_query = ''; + $tabid = getTabid($module); + + if($is_admin==false && $profileGlobalPermission[1] == 1 && $profileGlobalPermission[2] == 1 + && $defaultOrgSharingPermission[$tabid] == 3) { + + $sec_query .= " AND (vtiger_crmentity.smownerid in($current_user->id) OR vtiger_crmentity.smownerid IN + ( + SELECT vtiger_user2role.userid FROM vtiger_user2role + INNER JOIN vtiger_users ON vtiger_users.id=vtiger_user2role.userid + INNER JOIN vtiger_role ON vtiger_role.roleid=vtiger_user2role.roleid + WHERE vtiger_role.parentrole LIKE '".$current_user_parent_role_seq."::%' + ) + OR vtiger_crmentity.smownerid IN + ( + SELECT shareduserid FROM vtiger_tmp_read_user_sharing_per + WHERE userid=".$current_user->id." AND tabid=".$tabid." + ) + OR + ("; + + // Build the query based on the group association of current user. + if(sizeof($current_user_groups) > 0) { + $sec_query .= " vtiger_groups.groupid IN (". implode(",", $current_user_groups) .") OR "; + } + $sec_query .= " vtiger_groups.groupid IN + ( + SELECT vtiger_tmp_read_group_sharing_per.sharedgroupid + FROM vtiger_tmp_read_group_sharing_per + WHERE userid=".$current_user->id." and tabid=".$tabid." + )"; + $sec_query .= ") + )"; + } + return $sec_query; + } + + /** + * Create query to export the records. + */ + function create_export_query($where) + { + global $current_user; + $thismodule = $_REQUEST['module']; + + include("include/utils/ExportUtils.php"); + + //To get the Permitted fields query and the permitted fields list + $sql = getPermittedFieldsQuery($thismodule, "detail_view"); + + $fields_list = getFieldsListFromQuery($sql); + + $query = "SELECT $fields_list, vtiger_users.user_name AS user_name + FROM vtiger_crmentity INNER JOIN $this->table_name ON vtiger_crmentity.crmid=$this->table_name.$this->table_index"; + + if(!empty($this->customFieldTable)) { + $query .= " INNER JOIN ".$this->customFieldTable[0]." ON ".$this->customFieldTable[0].'.'.$this->customFieldTable[1] . + " = $this->table_name.$this->table_index"; + } + + $query .= " LEFT JOIN vtiger_groups ON vtiger_groups.groupid = vtiger_crmentity.smownerid"; + $query .= " LEFT JOIN vtiger_users ON vtiger_crmentity.smownerid = vtiger_users.id and vtiger_users.status='Active'"; + + $linkedModulesQuery = $this->db->pquery("SELECT distinct fieldname, columnname, relmodule FROM vtiger_field" . + " INNER JOIN vtiger_fieldmodulerel ON vtiger_fieldmodulerel.fieldid = vtiger_field.fieldid" . + " WHERE uitype='10' AND vtiger_fieldmodulerel.module=?", array($thismodule)); + $linkedFieldsCount = $this->db->num_rows($linkedModulesQuery); + + for($i=0; $i<$linkedFieldsCount; $i++) { + $related_module = $this->db->query_result($linkedModulesQuery, $i, 'relmodule'); + $fieldname = $this->db->query_result($linkedModulesQuery, $i, 'fieldname'); + $columnname = $this->db->query_result($linkedModulesQuery, $i, 'columnname'); + + $other = CRMEntity::getInstance($related_module); + vtlib_setup_modulevars($related_module, $other); + + $query .= " LEFT JOIN $other->table_name ON $other->table_name.$other->table_index = $this->table_name.$columnname"; + } + + $where_auto = " vtiger_crmentity.deleted=0"; + + if($where != '') $query .= " WHERE ($where) AND $where_auto"; + else $query .= " WHERE $where_auto"; + + require('user_privileges/user_privileges_'.$current_user->id.'.php'); + require('user_privileges/sharing_privileges_'.$current_user->id.'.php'); + + // Security Check for Field Access + if($is_admin==false && $profileGlobalPermission[1] == 1 && $profileGlobalPermission[2] == 1 && $defaultOrgSharingPermission[7] == 3) + { + //Added security check to get the permitted records only + $query = $query." ".getListViewSecurityParameter($thismodule); + } + return $query; + } + + /** + * Initialize this instance for importing. + */ + function initImport($module) { + $this->db = PearDatabase::getInstance(); + $this->initImportableFields($module); + } + + /** + * Create list query to be shown at the last step of the import. + * Called From: modules/Import/UserLastImport.php + */ + function create_import_query($module) { + global $current_user; + $query = "SELECT vtiger_crmentity.crmid, case when (vtiger_users.user_name not like '') then vtiger_users.user_name else vtiger_groups.groupname end as user_name, $this->table_name.* FROM $this->table_name + INNER JOIN vtiger_crmentity ON vtiger_crmentity.crmid = $this->table_name.$this->table_index + LEFT JOIN vtiger_users_last_import ON vtiger_users_last_import.bean_id=vtiger_crmentity.crmid + LEFT JOIN vtiger_users ON vtiger_users.id = vtiger_crmentity.smownerid + LEFT JOIN vtiger_groups ON vtiger_groups.groupid = vtiger_crmentity.smownerid + WHERE vtiger_users_last_import.assigned_user_id='$current_user->id' + AND vtiger_users_last_import.bean_type='$module' + AND vtiger_users_last_import.deleted=0"; + return $query; + } + + /** + * Delete the last imported records. + */ + function undo_import($module, $user_id) { + global $adb; + $count = 0; + $query1 = "select bean_id from vtiger_users_last_import where assigned_user_id=? AND bean_type='$module' AND deleted=0"; + $result1 = $adb->pquery($query1, array($user_id)) or die("Error getting last import for undo: ".mysql_error()); + while ( $row1 = $adb->fetchByAssoc($result1)) + { + $query2 = "update vtiger_crmentity set deleted=1 where crmid=?"; + $result2 = $adb->pquery($query2, array($row1['bean_id'])) or die("Error undoing last import: ".mysql_error()); + $count++; + } + return $count; + } + + /** + * Transform the value while exporting + */ + function transform_export_value($key, $value) { + return parent::transform_export_value($key, $value); + } + + /** + * Function which will set the assigned user id for import record. + */ + function set_import_assigned_user() + { + global $current_user, $adb; + $record_user = $this->column_fields["assigned_user_id"]; + + if($record_user != $current_user->id){ + $sqlresult = $adb->pquery("select id from vtiger_users where id = ? union select groupid as id from vtiger_groups where groupid = ?", array($record_user, $record_user)); + if($this->db->num_rows($sqlresult)!= 1) { + $this->column_fields["assigned_user_id"] = $current_user->id; + } else { + $row = $adb->fetchByAssoc($sqlresult, -1, false); + if (isset($row['id']) && $row['id'] != -1) { + $this->column_fields["assigned_user_id"] = $row['id']; + } else { + $this->column_fields["assigned_user_id"] = $current_user->id; + } + } + } + } + + /** + * Function which will give the basic query to find duplicates + */ + function getDuplicatesQuery($module,$table_cols,$field_values,$ui_type_arr,$select_cols='') { + $select_clause = "SELECT ". $this->table_name .".".$this->table_index ." AS recordid, vtiger_users_last_import.deleted,".$table_cols; + + // Select Custom Field Table Columns if present + if(isset($this->customFieldTable)) $query .= ", " . $this->customFieldTable[0] . ".* "; + + $from_clause = " FROM $this->table_name"; + + $from_clause .= " INNER JOIN vtiger_crmentity ON vtiger_crmentity.crmid = $this->table_name.$this->table_index"; + + // Consider custom table join as well. + if(isset($this->customFieldTable)) { + $from_clause .= " INNER JOIN ".$this->customFieldTable[0]." ON ".$this->customFieldTable[0].'.'.$this->customFieldTable[1] . + " = $this->table_name.$this->table_index"; + } + $from_clause .= " LEFT JOIN vtiger_users ON vtiger_users.id = vtiger_crmentity.smownerid + LEFT JOIN vtiger_groups ON vtiger_groups.groupid = vtiger_crmentity.smownerid"; + + $where_clause = " WHERE vtiger_crmentity.deleted = 0"; + $where_clause .= $this->getListViewSecurityParameter($module); + + if (isset($select_cols) && trim($select_cols) != '') { + $sub_query = "SELECT $select_cols FROM $this->table_name AS t " . + " INNER JOIN vtiger_crmentity AS crm ON crm.crmid = t.".$this->table_index; + // Consider custom table join as well. + if(isset($this->customFieldTable)) { + $sub_query .= " LEFT JOIN ".$this->customFieldTable[0]." tcf ON tcf.".$this->customFieldTable[1]." = t.$this->table_index"; + } + $sub_query .= " WHERE crm.deleted=0 GROUP BY $select_cols HAVING COUNT(*)>1"; + } else { + $sub_query = "SELECT $table_cols $from_clause $where_clause GROUP BY $table_cols HAVING COUNT(*)>1"; + } + + + $query = $select_clause . $from_clause . + " LEFT JOIN vtiger_users_last_import ON vtiger_users_last_import.bean_id=" . $this->table_name .".".$this->table_index . + " INNER JOIN (" . $sub_query . ") AS temp ON ".get_on_clause($field_values,$ui_type_arr,$module) . + $where_clause . + " ORDER BY $table_cols,". $this->table_name .".".$this->table_index ." ASC"; + + return $query; + } + + /** + * Invoked when special actions are performed on the module. + * @param String Module name + * @param String Event Type (module.postinstall, module.disabled, module.enabled, module.preuninstall) + */ + function vtlib_handler($modulename, $event_type) { + if($event_type == 'module.postinstall') { + // TODO Handle post installation actions + } else if($event_type == 'module.disabled') { + // TODO Handle actions when this module is disabled. + } else if($event_type == 'module.enabled') { + // TODO Handle actions when this module is enabled. + } else if($event_type == 'module.preuninstall') { + // TODO Handle actions when this module is about to be deleted. + } else if($event_type == 'module.preupdate') { + // TODO Handle actions before this module is updated. + } else if($event_type == 'module.postupdate') { + // TODO Handle actions after this module is updated. + } + } + + /** + * Handle saving related module information. + * NOTE: This function has been added to CRMEntity (base class). + * You can override the behavior by re-defining it here. + */ + // function save_related_module($module, $crmid, $with_module, $with_crmid) { } + + /** + * Handle deleting related module information. + * NOTE: This function has been added to CRMEntity (base class). + * You can override the behavior by re-defining it here. + */ + //function delete_related_module($module, $crmid, $with_module, $with_crmid) { } + + /** + * Handle getting related list information. + * NOTE: This function has been added to CRMEntity (base class). + * You can override the behavior by re-defining it here. + */ + //function get_related_list($id, $cur_tab_id, $rel_tab_id, $actions=false) { } + + /** + * Handle getting dependents list information. + * NOTE: This function has been added to CRMEntity (base class). + * You can override the behavior by re-defining it here. + */ + //function get_dependents_list($id, $cur_tab_id, $rel_tab_id, $actions=false) { } +} +?> \ No newline at end of file diff --git a/oss/vtiger/trunk/vtlib/ModuleDir/5.1.0/ModuleFileAjax.php b/oss/vtiger/trunk/vtlib/ModuleDir/5.1.0/ModuleFileAjax.php new file mode 100644 index 00000000..efae0a94 --- /dev/null +++ b/oss/vtiger/trunk/vtlib/ModuleDir/5.1.0/ModuleFileAjax.php @@ -0,0 +1,11 @@ + diff --git a/oss/vtiger/trunk/vtlib/ModuleDir/5.1.0/Popup.php b/oss/vtiger/trunk/vtlib/ModuleDir/5.1.0/Popup.php new file mode 100644 index 00000000..40aae3fa --- /dev/null +++ b/oss/vtiger/trunk/vtlib/ModuleDir/5.1.0/Popup.php @@ -0,0 +1,11 @@ + diff --git a/oss/vtiger/trunk/vtlib/ModuleDir/5.1.0/ProcessDuplicates.php b/oss/vtiger/trunk/vtlib/ModuleDir/5.1.0/ProcessDuplicates.php new file mode 100644 index 00000000..bb5047fa --- /dev/null +++ b/oss/vtiger/trunk/vtlib/ModuleDir/5.1.0/ProcessDuplicates.php @@ -0,0 +1,134 @@ +pquery("SELECT count(*) AS count FROM vtiger_crmentity WHERE crmid=? and deleted=0", array($merge_id)); + $count = $adb->query_result($result,0,'count'); + + if($count > 0) + { + // First, save the primary record + $focus->mode="edit"; + setObjectValuesFromRequest($focus); + $focus->save($module); + $rec_values=$focus->column_fields; + + // Remove the id of primary record from the list of records to be deleted. + $del_value=explode(",",$recordids,-1); + $offset = array_search($merge_id,$del_value); + unset($del_value[$offset]); + + // Transfer the related lists of the records to be deleted, to the primary record's related list + if(method_exists($focus, 'transferRelatedRecords')){ + $focus->transferRelatedRecords($module,$del_value,$merge_id); + } else { + transferRelatedRecords($module,$del_value,$merge_id); + } + + // Delete the records by id specified in the list + foreach($del_value as $value) + { + DeleteEntity($_REQUEST['module'],$_REQUEST['return_module'],$focus,$value,""); + } + } + + ?> + +assign("EDIT_DUPLICATE",""); + if($record_count == 2) { + if(isPermitted($currentModule,"EditView",$exploded_id[0]) == 'yes' && isPermitted($currentModule,"EditView",$exploded_id[1]) == 'yes' + && isPermitted($currentModule,"Delete",$exploded_id[0]) == 'yes' && isPermitted($currentModule,"Delete",$exploded_id[1]) == 'yes') + $smarty->assign("EDIT_DUPLICATE","permitted"); + } + else { + if(isPermitted($currentModule,"EditView",$exploded_id[0]) == 'yes' && isPermitted($currentModule,"EditView",$exploded_id[1]) == 'yes' && isPermitted($currentModule,"EditView",$exploded_id[2]) == 'yes' + && isPermitted($currentModule,"Delete",$exploded_id[0]) == 'yes' && isPermitted($currentModule,"Delete",$exploded_id[1]) == 'yes' && isPermitted($currentModule,"Delete",$exploded_id[2]) == 'yes') + $smarty->assign("EDIT_DUPLICATE","permitted"); + } + + $all_values_array=getRecordValues($exploded_id,$module); + $all_values=$all_values_array[0]; + $js_arr_val=$all_values_array[1]; + $fld_array=$all_values_array[2]; + $js_arr=implode(",",$js_arr_val); + + $imported_records = Array(); + $sql="select bean_id from vtiger_users_last_import where bean_type=? and deleted=0"; + $result = $adb->pquery($sql, array($module)); + $num_rows=$adb->num_rows($result); + $count=0; + for($i=0; $i<$num_rows;$i++) + { + foreach($exploded_id as $value) + if($value == $adb->query_result($result,$i,"bean_id")) + $count++; + array_push($imported_records,$adb->query_result($result,$i,"bean_id")); + } + + if ($record_count == $count) + $no_existing=1; + else + $no_existing=0; + + $smarty->assign("MOD", $mod_strings); + $smarty->assign("APP", $app_strings); + $smarty->assign("RECORD_COUNT",$record_count); + $smarty->assign("THEME", $theme); + $smarty->assign("IMAGE_PATH", $image_path); + $smarty->assign("MODULENAME", $module); + $smarty->assign("PARENT_TAB", $parent_tab); + $smarty->assign("JS_ARRAY", $js_arr); + $smarty->assign("ID_ARRAY", $exploded_id); + $smarty->assign("IDSTRING",$idstring); + $smarty->assign("ALLVALUES", $all_values); + $smarty->assign("FIELD_ARRAY", $fld_array); + $smarty->assign("IMPORTED_RECORDS", $imported_records); + $smarty->assign("NO_EXISTING", $no_existing); + $smarty->display("MergeFields.tpl"); +} + +?> diff --git a/oss/vtiger/trunk/vtlib/ModuleDir/5.1.0/QuickCreate.php b/oss/vtiger/trunk/vtlib/ModuleDir/5.1.0/QuickCreate.php new file mode 100644 index 00000000..78fe10f6 --- /dev/null +++ b/oss/vtiger/trunk/vtlib/ModuleDir/5.1.0/QuickCreate.php @@ -0,0 +1,11 @@ + diff --git a/oss/vtiger/trunk/vtlib/ModuleDir/5.1.0/Save.php b/oss/vtiger/trunk/vtlib/ModuleDir/5.1.0/Save.php new file mode 100644 index 00000000..b595d9e1 --- /dev/null +++ b/oss/vtiger/trunk/vtlib/ModuleDir/5.1.0/Save.php @@ -0,0 +1,53 @@ +mode = $mode; +if($record)$focus->id = $record; + +if($_REQUEST['assigntype'] == 'U') { + $focus->column_fields['assigned_user_id'] = $_REQUEST['assigned_user_id']; +} elseif($_REQUEST['assigntype'] == 'T') { + $focus->column_fields['assigned_user_id'] = $_REQUEST['assigned_group_id']; +} + +$focus->save($currentModule); +$return_id = $focus->id; + +$search = vtlib_purify($_REQUEST['search_url']); + +$parenttab = getParentTab(); +if($_REQUEST['return_module'] != '') { + $return_module = vtlib_purify($_REQUEST['return_module']); +} else { + $return_module = $currentModule; +} + +if($_REQUEST['return_action'] != '') { + $return_action = vtlib_purify($_REQUEST['return_action']); +} else { + $return_action = "DetailView"; +} + +if($_REQUEST['return_id'] != '') { + $return_id = vtlib_purify($_REQUEST['return_id']); +} + +header("Location: index.php?action=$return_action&module=$return_module&record=$return_id&parenttab=$parenttab&start=".vtlib_purify($_REQUEST['pagenumber']).$search); + +?> \ No newline at end of file diff --git a/oss/vtiger/trunk/vtlib/ModuleDir/5.1.0/Settings.php b/oss/vtiger/trunk/vtlib/ModuleDir/5.1.0/Settings.php new file mode 100644 index 00000000..980dd078 --- /dev/null +++ b/oss/vtiger/trunk/vtlib/ModuleDir/5.1.0/Settings.php @@ -0,0 +1,13 @@ + diff --git a/oss/vtiger/trunk/vtlib/ModuleDir/5.1.0/TagCloud.php b/oss/vtiger/trunk/vtlib/ModuleDir/5.1.0/TagCloud.php new file mode 100644 index 00000000..8343cd5b --- /dev/null +++ b/oss/vtiger/trunk/vtlib/ModuleDir/5.1.0/TagCloud.php @@ -0,0 +1,11 @@ + diff --git a/oss/vtiger/trunk/vtlib/ModuleDir/5.1.0/UnifiedSearch.php b/oss/vtiger/trunk/vtlib/ModuleDir/5.1.0/UnifiedSearch.php new file mode 100644 index 00000000..9a37320c --- /dev/null +++ b/oss/vtiger/trunk/vtlib/ModuleDir/5.1.0/UnifiedSearch.php @@ -0,0 +1,11 @@ + \ No newline at end of file diff --git a/oss/vtiger/trunk/vtlib/ModuleDir/5.1.0/index.php b/oss/vtiger/trunk/vtlib/ModuleDir/5.1.0/index.php new file mode 100644 index 00000000..b7add8d8 --- /dev/null +++ b/oss/vtiger/trunk/vtlib/ModuleDir/5.1.0/index.php @@ -0,0 +1,15 @@ + diff --git a/oss/vtiger/trunk/vtlib/ModuleDir/5.1.0/language/en_us.lang.php b/oss/vtiger/trunk/vtlib/ModuleDir/5.1.0/language/en_us.lang.php new file mode 100644 index 00000000..73777036 --- /dev/null +++ b/oss/vtiger/trunk/vtlib/ModuleDir/5.1.0/language/en_us.lang.php @@ -0,0 +1,20 @@ + 'Module Name', + + 'LBL_CUSTOM_INFORMATION' => 'Custom Information', + 'LBL_MODULEBLOCK_INFORMATION' => 'ModuleBlock Information', + + 'ModuleFieldLabel' => 'ModuleFieldLabel Text', +); + +?> diff --git a/oss/vtiger/trunk/vtlib/ModuleDir/5.1.0/updateRelations.php b/oss/vtiger/trunk/vtlib/ModuleDir/5.1.0/updateRelations.php new file mode 100644 index 00000000..9ee5399f --- /dev/null +++ b/oss/vtiger/trunk/vtlib/ModuleDir/5.1.0/updateRelations.php @@ -0,0 +1,46 @@ +delete_related_module($currentModule, $forCRMRecord, $destinationModule, $ids); + } +} else { + if(!empty($_REQUEST['idlist'])) { + // Split the string of ids + $ids = explode (";",trim($idlist,";")); + } else if(!empty($_REQUEST['entityid'])){ + $ids = $_REQUEST['entityid']; + } + if(!empty($ids)) { + $focus->save_related_module($currentModule, $forCRMRecord, $destinationModule, $ids); + } +} +header("Location: index.php?module=$currentModule&record=$forCRMRecord&action=$action&parenttab=$parenttab"); +?> \ No newline at end of file diff --git a/oss/vtiger/trunk/vtlib/README-UsingModuleDir.txt b/oss/vtiger/trunk/vtlib/README-UsingModuleDir.txt new file mode 100644 index 00000000..1d3451f4 --- /dev/null +++ b/oss/vtiger/trunk/vtlib/README-UsingModuleDir.txt @@ -0,0 +1,27 @@ +Using skeleton module +===================== + +1. Copy ModuleDir/ to modules/ +2. Rename modules//ModuleFile.php to .php +3. Rename modules//ModuleFileAjax.php to Ajax.php +4. Rename modules//ModuleFile.js to .js + +5. Edit .php + + a. Update $table_name and $table_index (Module table name and table index column) + + b. Update $groupTable + + c. Update $tab_name, $tab_name_index + + d. Update $list_fields, $list_fields_name, $sortby_fields + + e. Update $detailview_links + + f. Update $default_order_by, $default_sort_order + + g. Update $customFieldTable + + h. Rename class ModuleClass to class + +Refer documentation for more details. \ No newline at end of file diff --git a/oss/vtiger/trunk/vtlib/Vtiger/Access.php b/oss/vtiger/trunk/vtlib/Vtiger/Access.php new file mode 100644 index 00000000..3d7efd84 --- /dev/null +++ b/oss/vtiger/trunk/vtlib/Vtiger/Access.php @@ -0,0 +1,181 @@ +getUniqueID('vtiger_def_org_share'); + } + + /** + * Recalculate sharing access rules. + * @internal This function could take up lot of resource while execution + * @access private + */ + static function syncSharingAccess() { + self::log("Recalculating sharing rules ... ", false); + RecalculateSharingRules(); + self::log("DONE"); + } + + /** + * Enable or Disable sharing access control to module + * @param Vtiger_Module Instance of the module to use + * @param Boolean true to enable sharing access, false disable sharing access + * @access private + */ + static function allowSharing($moduleInstance, $enable=true) { + global $adb; + $ownedby = $enable? 0 : 1; + $adb->pquery("UPDATE vtiger_tab set ownedby=? WHERE tabid=?", Array($ownedby, $moduleInstance->id)); + self::log(($enable? "Enabled" : "Disabled") . " sharing access control ... DONE"); + } + + /** + * Initialize sharing access. + * @param Vtiger_Module Instance of the module to use + * @access private + * @internal This method is called from Vtiger_Module during creation. + */ + static function initSharing($moduleInstance) { + global $adb; + + $result = $adb->query("SELECT share_action_id from vtiger_org_share_action_mapping WHERE share_action_name in + ('Public: Read Only', 'Public: Read, Create/Edit', 'Public: Read, Create/Edit, Delete', 'Private')"); + + for($index = 0; $index < $adb->num_rows($result); ++$index) { + $actionid = $adb->query_result($result, $index, 'share_action_id'); + $adb->pquery("INSERT INTO vtiger_org_share_action2tab(share_action_id,tabid) VALUES(?,?)", Array($actionid, $moduleInstance->id)); + } + self::log("Setting up sharing access options ... DONE"); + } + + /** + * Delete sharing access setup for module + * @param Vtiger_Module Instance of module to use + * @access private + * @internal This method is called from Vtiger_Module during deletion. + */ + static function deleteSharing($moduleInstance) { + global $adb; + $adb->pquery("DELETE FROM vtiger_org_share_action2tab WHERE tabid=?", Array($moduleInstance->id)); + self::log("Deleting sharing access ... DONE"); + } + + /** + * Set default sharing for a module + * @param Vtiger_Module Instance of the module + * @param String Permission text should be one of ['Public_ReadWriteDelete', 'Public_ReadOnly', 'Public_ReadWrite', 'Private'] + * @access private + */ + static function setDefaultSharing($moduleInstance, $permission_text='Public_ReadWriteDelete') { + global $adb; + + $permission_text = strtolower($permission_text); + + if($permission_text == 'public_readonly') $permission = 0; + else if($permission_text == 'public_readwrite') $permission = 1; + else if($permission_text == 'public_readwritedelete') $permission = 2; + else if($permission_text == 'private') $permission = 3; + else $permission = 2; // public_readwritedelete is default + + $editstatus = 0; // 0 or 1 + + $result = $adb->pquery("SELECT * FROM vtiger_def_org_share WHERE tabid=?", Array($moduleInstance->id)); + if($adb->num_rows($result)) { + $ruleid = $adb->query_result($result, 0, 'ruleid'); + $adb->pquery("UPDATE vtiger_def_org_share SET permission=? WHERE ruleid=?", Array($permission, $ruleid)); + } else { + $ruleid = self::__getDefaultSharingAccessId(); + $adb->pquery("INSERT INTO vtiger_def_org_share (ruleid,tabid,permission,editstatus) VALUES(?,?,?,?)", + Array($ruleid,$moduleInstance->id,$permission,$editstatus)); + } + + self::syncSharingAccess(); + } + + /** + * Enable tool for module. + * @param Vtiger_Module Instance of module to use + * @param String Tool (action name) like Import, Export, Merge + * @param Boolean true to enable tool, false to disable + * @param Integer (optional) profile id to use, false applies to all profile. + * @access private + */ + static function updateTool($moduleInstance, $toolAction, $flag, $profileid=false) { + global $adb; + + $result = $adb->pquery("SELECT actionid FROM vtiger_actionmapping WHERE actionname=?", Array($toolAction)); + if($adb->num_rows($result)) { + $actionid = $adb->query_result($result, 0, 'actionid'); + $permission = ($flag == true)? '0' : '1'; + + $profileids = Array(); + if($profileid) { + $profileids[] = $profileid; + } else { + $profileids = Vtiger_Profile::getAllIds(); + } + + self::log( ($flag? 'Enabling':'Disabling') . " $toolAction for Profile [", false); + + foreach($profileids as $useprofileid) { + $result = $adb->pquery("SELECT permission FROM vtiger_profile2utility WHERE profileid=? AND tabid=? AND activityid=?", + Array($useprofileid, $moduleInstance->id, $actionid)); + if($adb->num_rows($result)) { + $curpermission = $adb->query_result($result, 0, 'permission'); + if($curpermission != $permission) { + $adb->pquery("UPDATE vtiger_profile2utility set permission=? WHERE profileid=? AND tabid=? AND activityid=?", + Array($permission, $useprofileid, $moduleInstance->id, $actionid)); + } + } else { + $adb->pquery("INSERT INTO vtiger_profile2utility (profileid, tabid, activityid, permission) VALUES(?,?,?,?)", + Array($useprofileid, $moduleInstance->id, $actionid, $permission)); + } + + self::log("$useprofileid,", false); + } + self::log("] ... DONE"); + } + } + + /** + * Delete tool (actions) of the module + * @param Vtiger_Module Instance of module to use + */ + static function deleteTools($moduleInstance) { + global $adb; + $adb->pquery("DELETE FROM vtiger_profile2utility WHERE tabid=?", Array($moduleInstance->id)); + self::log("Deleting tools ... DONE"); + } +} +?> diff --git a/oss/vtiger/trunk/vtlib/Vtiger/Block.php b/oss/vtiger/trunk/vtlib/Vtiger/Block.php new file mode 100644 index 00000000..24735625 --- /dev/null +++ b/oss/vtiger/trunk/vtlib/Vtiger/Block.php @@ -0,0 +1,215 @@ +getUniqueID('vtiger_blocks'); + return $maxblockid; + } + + /** + * Get next sequence value to use for this block instance + * @access private + */ + function __getNextSequence() { + global $adb; + $result = $adb->pquery("SELECT MAX(sequence) as max_sequence from vtiger_blocks where tabid = ?", Array($this->module->id)); + $maxseq = 0; + if($adb->num_rows($result)) { + $maxseq = $adb->query_result($result, 0, 'max_sequence'); + } + return ++$maxseq; + } + + /** + * Initialize this block instance + * @param Array Map of column name and value + * @param Vtiger_Module Instance of module to which this block is associated + * @access private + */ + function initialize($valuemap, $moduleInstance=false) { + $this->id = $valuemap[blockid]; + $this->label= $valuemap[blocklabel]; + $this->module=$moduleInstance? $moduleInstance: Vtiger_Module::getInstance($valuemap[tabid]); + } + + /** + * Create vtiger CRM block + * @access private + */ + function __create($moduleInstance) { + global $adb; + + $this->module = $moduleInstance; + + $this->id = $this->__getUniqueId(); + if(!$this->sequence) $this->sequence = $this->__getNextSequence(); + + $adb->pquery("INSERT INTO vtiger_blocks(blockid,tabid,blocklabel,sequence,show_title,visible,create_view,edit_view,detail_view) + VALUES(?,?,?,?,?,?,?,?,?)", Array($this->id, $this->module->id, $this->label,$this->sequence, + $this->showtitle, $this->visible,$this->increateview, $this->ineditview, $this->indetailview)); + self::log("Creating Block $this->label ... DONE"); + self::log("Module language entry for $this->label ... CHECK"); + } + + /** + * Update vtiger CRM block + * @access private + * @internal TODO + */ + function __update() { + self::log("Updating Block $this->label ... DONE"); + } + + /** + * Delete this instance + * @access private + */ + function __delete() { + global $adb; + self::log("Deleting Block $this->label ... ", false); + $adb->pquery("DELETE FROM vtiger_blocks WHERE blockid=?", Array($this->id)); + self::log("DONE"); + } + + /** + * Save this block instance + * @param Vtiger_Module Instance of the module to which this block is associated + */ + function save($moduleInstance=false) { + if($this->id) $this->__update(); + else $this->__create($moduleInstance); + return $this->id; + } + + /** + * Delete block instance + * @param Boolean True to delete associated fields, False to avoid it + */ + function delete($recursive=true) { + if($recursive) { + $fields = Vtiger_Field::getAllForBlock($this); + foreach($fields as $fieldInstance) $fieldInstance->delete($recursive); + } + $this->__delete(); + } + + /** + * Add field to this block + * @param Vtiger_Field Instance of field to add to this block. + * @return Reference to this block instance + */ + function addField($fieldInstance) { + $fieldInstance->save($this); + return $this; + } + + /** + * Helper function to log messages + * @param String Message to log + * @param Boolean true appends linebreak, false to avoid it + * @access private + */ + static function log($message, $delim=true) { + Vtiger_Utils::Log($message, $delim); + } + + /** + * Get instance of block + * @param mixed block id or block label + * @param Vtiger_Module Instance of the module if block label is passed + */ + static function getInstance($value, $moduleInstance=false) { + global $adb; + $instance = false; + + $query = false; + $queryParams = false; + if(Vtiger_Utils::isNumber($value)) { + $query = "SELECT * FROM vtiger_blocks WHERE blockid=?"; + $queryParams = Array($value); + } else { + $query = "SELECT * FROM vtiger_blocks WHERE blocklabel=? AND tabid=?"; + $queryParams = Array($value, $moduleInstance->id); + } + $result = $adb->pquery($query, $queryParams); + if($adb->num_rows($result)) { + $instance = new self(); + $instance->initialize($adb->fetch_array($result), $moduleInstance); + } + return $instance; + } + + /** + * Get all block instances associated with the module + * @param Vtiger_Module Instance of the module + */ + static function getAllForModule($moduleInstance) { + global $adb; + $instances = false; + + $query = "SELECT * FROM vtiger_blocks WHERE tabid=?"; + $queryParams = Array($moduleInstance->id); + + $result = $adb->pquery($query, $queryParams); + for($index = 0; $index < $adb->num_rows($result); ++$index) { + $instance = new self(); + $instance->initialize($adb->fetch_array($result), $moduleInstance); + $instances[] = $instance; + } + return $instances; + } + + /** + * Delete all blocks associated with module + * @param Vtiger_Module Instnace of module to use + * @param Boolean true to delete associated fields, false otherwise + * @access private + */ + static function deleteForModule($moduleInstance, $recursive=true) { + global $adb; + if($recursive) Vtiger_Field::deleteForModule($moduleInstance); + $adb->pquery("DELETE FROM vtiger_blocks WHERE tabid=?", Array($moduleInstance->id)); + self::log("Deleting blocks for module ... DONE"); + } +} +?> diff --git a/oss/vtiger/trunk/vtlib/Vtiger/Event.php b/oss/vtiger/trunk/vtlib/Vtiger/Event.php new file mode 100644 index 00000000..4fd46787 --- /dev/null +++ b/oss/vtiger/trunk/vtlib/Vtiger/Event.php @@ -0,0 +1,127 @@ +registerHandler($eventname, $filename, $classname, $condition); + $eventsManager->setModuleForHandler($moduleInstance->name, $classname); + + self::log("Registering Event $eventname with [$filename] $classname ... DONE"); + } + } + + /** + * Trigger event based on CRM Record + * @param String Name of the Event to trigger + * @param Integer CRM record id on which event needs to be triggered. + */ + static function trigger($eventname, $crmid) { + if(!self::hasSupport()) return; + + global $adb; + $checkres = $adb->pquery("SELECT setype, crmid, deleted FROM vtiger_crmentity WHERE crmid=?", Array($crmid)); + if($adb->num_rows($checkres)) { + $result = $adb->fetch_array($checkres, 0); + if($result['deleted'] == '0') { + $module = $result['setype']; + $moduleInstance = CRMEntity::getInstance($module); + $moduleInstance->retrieve_entity_info($result['crmid'], $module); + $moduleInstance->id = $result['crmid']; + + global $current_user; + if(!$current_user) { + $current_user = new Users(); + $current_user->id = $moduleInstance->column_fields['assigned_user_id']; + } + + // Trigger the event + $em = new VTEventsManager($adb); + $em->triggerEvent($eventname, VTEntityData::fromCRMEntity($moduleInstance)); + } + } + } + + /** + * Get all the registered module events + * @param Vtiger_Module Instance of the module to use + */ + static function getAll($moduleInstance) { + global $adb; + $events = false; + if(self::hasSupport()) { + // Get all events related to module + $records = $adb->pquery("SELECT * FROM vtiger_eventhandlers WHERE handler_class IN + (SELECT handler_class FROM vtiger_eventhandler_module WHERE module_name=?)", Array($moduleInstance->name)); + if($records) { + while($record = $adb->fetch_array($records)) { + $event = new Vtiger_Event(); + $event->eventname = $record['event_name']; + $event->classname = $record['handler_class']; + $event->filename = $record['handler_path']; + $event->condition = $record['condition']; + $events[] = $event; + } + } + } + return $events; + } +} +?> \ No newline at end of file diff --git a/oss/vtiger/trunk/vtlib/Vtiger/Feed/Parser.php b/oss/vtiger/trunk/vtlib/Vtiger/Feed/Parser.php new file mode 100644 index 00000000..776cdf23 --- /dev/null +++ b/oss/vtiger/trunk/vtlib/Vtiger/Feed/Parser.php @@ -0,0 +1,44 @@ +set_timeout($timeout); + $this->set_feed_url($url); + $this->enable_order_by_date(false); + $this->enable_cache(false); + $this->init(); + $this->vt_fetchdone = true; + } + + /** + * Parse the content as feed. + * @param String Feed content + */ + function vt_doparse($content) { + $this->set_raw_data($content); + $this->init(); + $this->vt_fetchdone = true; + } +} +?> diff --git a/oss/vtiger/trunk/vtlib/Vtiger/Field.php b/oss/vtiger/trunk/vtlib/Vtiger/Field.php new file mode 100644 index 00000000..8ce85f2a --- /dev/null +++ b/oss/vtiger/trunk/vtlib/Vtiger/Field.php @@ -0,0 +1,245 @@ +getUniqueID('vtiger_picklist'); + } + + /** + * Set values for picklist field (for all the roles) + * @param Array List of values to add. + * + * @internal Creates picklist base if it does not exists + */ + function setPicklistValues($values) { + global $adb; + + // Non-Role based picklist values + if($this->uitype == '16') { + $this->setNoRolePicklistValues($values); + return; + } + + $picklist_table = 'vtiger_'.$this->name; + $picklist_idcol = $this->name.'id'; + + if(!Vtiger_Utils::CheckTable($picklist_table)) { + Vtiger_Utils::CreateTable( + $picklist_table, + "($picklist_idcol INT NOT NULL AUTO_INCREMENT PRIMARY KEY, + $this->name VARCHAR(200) NOT NULL, + presence INT (1) NOT NULL DEFAULT 1, + picklist_valueid INT NOT NULL DEFAULT 0)", + true); + $new_picklistid = $this->__getPicklistUniqueId(); + $adb->pquery("INSERT INTO vtiger_picklist (picklistid,name) VALUES(?,?)",Array($new_picklistid, $this->name)); + self::log("Creating table $picklist_table ... DONE"); + } else { + $new_picklistid = $adb->query_result( + $adb->pquery("SELECT picklistid FROM vtiger_picklist WHERE name=?", Array($this->name)), 0, 'picklistid'); + } + + // Add value to picklist now + $sortid = 0; // TODO To be set per role + foreach($values as $value) { + $new_picklistvalueid = getUniquePicklistID(); + $presence = 1; // 0 - readonly, Refer function in include/ComboUtil.php + $new_id = $adb->getUniqueID($picklist_table); + $adb->pquery("INSERT INTO $picklist_table($picklist_idcol, $this->name, presence, picklist_valueid) VALUES(?,?,?,?)", + Array($new_id, $value, $presence, $new_picklistvalueid)); + ++$sortid; + + // Associate picklist values to all the role + $adb->query("INSERT INTO vtiger_role2picklist(roleid, picklistvalueid, picklistid, sortid) SELECT roleid, + $new_picklistvalueid, $new_picklistid, $sortid FROM vtiger_role"); + } + } + + /** + * Set values for picklist field (non-role based) + * @param Array List of values to add + * + * @internal Creates picklist base if it does not exists + * @access private + */ + function setNoRolePicklistValues($values) { + global $adb; + + $picklist_table = 'vtiger_'.$this->name; + $picklist_idcol = $this->name.'id'; + + if(!Vtiger_Utils::CheckTable($picklist_table)) { + Vtiger_Utils::CreateTable( + $picklist_table, + "($picklist_idcol INT NOT NULL AUTO_INCREMENT PRIMARY KEY, + $this->name VARCHAR(200) NOT NULL, + sortorderid INT(11), + presence INT (11) NOT NULL DEFAULT 1)", + true); + self::log("Creating table $picklist_table ... DONE"); + } + + // Add value to picklist now + $sortid = 1; + foreach($values as $value) { + $presence = 1; // 0 - readonly, Refer function in include/ComboUtil.php + $new_id = $adb->getUniqueId($picklist_table); + $adb->pquery("INSERT INTO $picklist_table($picklist_idcol, $this->name, sortorderid, presence) VALUES(?,?,?,?)", + Array($new_id, $value, $sortid, $presence)); + + $sortid = $sortid+1; + } + } + + /** + * Set relation between field and modules (UIType 10) + * @param Array List of module names + * + * @internal Creates table vtiger_fieldmodulerel if it does not exists + */ + function setRelatedModules($moduleNames) { + + // We need to create core table to capture the relation between the field and modules. + Vtiger_Utils::CreateTable( + 'vtiger_fieldmodulerel', + '(fieldid INT NOT NULL, module VARCHAR(100) NOT NULL, relmodule VARCHAR(100) NOT NULL, status VARCHAR(10), sequence INT)', + true + ); + // END + + global $adb; + foreach($moduleNames as $relmodule) { + $checkres = $adb->pquery('SELECT * FROM vtiger_fieldmodulerel WHERE fieldid=? AND module=? AND relmodule=?', + Array($this->id, $this->getModuleName(), $relmodule)); + + // If relation already exist continue + if($adb->num_rows($checkres)) continue; + + $adb->pquery('INSERT INTO vtiger_fieldmodulerel(fieldid, module, relmodule) VALUES(?,?,?)', + Array($this->id, $this->getModuleName(), $relmodule)); + + self::log("Setting $this->name relation with $relmodule ... DONE"); + } + return true; + } + + /** + * Remove relation between the field and modules (UIType 10) + * @param Array List of module names + */ + function unsetRelatedModules($moduleNames) { + global $adb; + foreach($moduleNames as $relmodule) { + $adb->pquery('DELETE FROM vtiger_fieldmodulerel WHERE fieldid=? AND module=? AND relmodule = ?', + Array($this->id, $this->getModuleName(), $relmodule)); + + Vtiger_Utils::Log("Unsetting $this->name relation with $relmodule ... DONE"); + } + return true; + } + + /** + * Get Vtiger_Field instance by fieldid or fieldname + * @param mixed fieldid or fieldname + * @param Vtiger_Module Instance of the module if fieldname is used + */ + static function getInstance($value, $moduleInstance=false) { + global $adb; + $instance = false; + + $query = false; + $queryParams = false; + if(Vtiger_Utils::isNumber($value)) { + $query = "SELECT * FROM vtiger_field WHERE fieldid=?"; + $queryParams = Array($value); + } else { + $query = "SELECT * FROM vtiger_field WHERE fieldname=? AND tabid=?"; + $queryParams = Array($value, $moduleInstance->id); + } + $result = $adb->pquery($query, $queryParams); + if($adb->num_rows($result)) { + $instance = new self(); + $instance->initialize($adb->fetch_array($result), $moduleInstance); + } + return $instance; + } + + /** + * Get Vtiger_Field instances related to block + * @param Vtiger_Block Instnace of block to use + * @param Vtiger_Module Instance of module to which block is associated + */ + static function getAllForBlock($blockInstance, $moduleInstance=false) { + global $adb; + $instances = false; + + $query = false; + $queryParams = false; + if($moduleInstance) { + $query = "SELECT * FROM vtiger_field WHERE block=? AND tabid=?"; + $queryParams = Array($blockInstance->id, $moduleInstance->id); + } else { + $query = "SELECT * FROM vtiger_field WHERE block=?"; + $queryParams = Array($blockInstance->id); + } + $result = $adb->pquery($query, $queryParams); + for($index = 0; $index < $adb->num_rows($result); ++$index) { + $instance = new self(); + $instance->initialize($adb->fetch_array($result), $moduleInstance, $blockInstance); + $instances[] = $instance; + } + return $instances; + } + + /** + * Get Vtiger_Field instances related to module + * @param Vtiger_Module Instance of module to use + */ + static function getAllForModule($moduleInstance) { + global $adb; + $instances = false; + + $query = "SELECT * FROM vtiger_field WHERE tabid=?"; + $queryParams = Array($moduleInstance->id); + + $result = $adb->pquery($query, $queryParams); + for($index = 0; $index < $adb->num_rows($result); ++$index) { + $instance = new self(); + $instance->initialize($adb->fetch_array($result), $moduleInstance); + $instances[] = $instance; + } + return $instances; + } + + /** + * Delete fields associated with the module + * @param Vtiger_Module Instance of module + * @access private + */ + static function deleteForModule($moduleInstance) { + global $adb; + $adb->pquery("DELETE FROM vtiger_field WHERE tabid=?", Array($moduleInstance->id)); + self::log("Deleting fields of the module ... DONE"); + } +} +?> diff --git a/oss/vtiger/trunk/vtlib/Vtiger/FieldBasic.php b/oss/vtiger/trunk/vtlib/Vtiger/FieldBasic.php new file mode 100644 index 00000000..16f5ccae --- /dev/null +++ b/oss/vtiger/trunk/vtlib/Vtiger/FieldBasic.php @@ -0,0 +1,283 @@ +id = $valuemap['fieldid']; + $this->name = $valuemap['fieldname']; + $this->label= $valuemap['fieldlabel']; + $this->column = $valuemap['columnname']; + $this->table = $valuemap['tablename']; + $this->uitype = $valuemap['uitype']; + $this->typeofdata = $valuemap['typeofdata']; + $this->helpinfo = $valuemap['helpinfo']; + $this->masseditable = $valuemap['masseditable']; + $this->block= $blockInstance? $blockInstance : Vtiger_Block::getInstance($valuemap['block'], $moduleInstance); + } + + /** Cache (Record) the schema changes to improve performance */ + static $__cacheSchemaChanges = Array(); + + /** + * Initialize vtiger schema changes. + * @access private + */ + function __handleVtigerCoreSchemaChanges() { + // Add helpinfo column to the vtiger_field table + if(empty(self::$__cacheSchemaChanges['vtiger_field.helpinfo'])) { + Vtiger_Utils::AddColumn('vtiger_field', 'helpinfo', ' TEXT'); + self::$__cacheSchemaChanges['vtiger_field.helpinfo'] = true; + } + } + + /** + * Get unique id for this instance + * @access private + */ + function __getUniqueId() { + global $adb; + return $adb->getUniqueID('vtiger_field'); + } + + /** + * Get next sequence id to use within a block for this instance + * @access private + */ + function __getNextSequence() { + global $adb; + $result = $adb->pquery("SELECT MAX(sequence) AS max_seq FROM vtiger_field WHERE tabid=? AND block=?", + Array($this->getModuleId(), $this->getBlockId())); + $maxseq = 0; + if($result && $adb->num_rows($result)) { + $maxseq = $adb->query_result($result, 0, 'max_seq'); + $maxseq += 1; + } + return $maxseq; + } + + /** + * Get next quick create sequence id for this instance + * @access private + */ + function __getNextQuickCreateSequence() { + global $adb; + $result = $adb->pquery("SELECT MAX(quickcreatesequence) AS max_quickcreateseq FROM vtiger_field WHERE tabid=?", + Array($this->getModuleId())); + $max_quickcreateseq = 0; + if($result && $adb->num_rows($result)) { + $max_quickcreateseq = $adb->query_result($result, 0, 'max_quickcreateseq'); + $max_quickcreateseq += 1; + } + return $max_quickcreateseq; + } + + /** + * Create this field instance + * @param Vtiger_Block Instance of the block to use + * @access private + */ + function __create($blockInstance) { + $this->__handleVtigerCoreSchemaChanges(); + + global $adb; + + $this->block = $blockInstance; + + $moduleInstance = $this->getModuleInstance(); + + $this->id = $this->__getUniqueId(); + + if(!$this->sequence) { + $this->sequence = $this->__getNextSequence(); + } + + if($this->quickcreate != 1) { // If enabled for display + if(!$this->quicksequence) { + $this->quicksequence = $this->__getNextQuickCreateSequence(); + } + } else { + $this->quicksequence = null; + } + + // Initialize other variables which are not done + if(!$this->table) $this->table = $moduleInstance->basetable; + if(!$this->column) { + $this->column = strtolower($this->name); + if(!$this->columntype) $this->columntype = 'VARCHAR(100)'; + } + + if(!$this->label) $this->label = $this->name; + + $adb->pquery("INSERT INTO vtiger_field (tabid, fieldid, columnname, tablename, generatedtype, + uitype, fieldname, fieldlabel, readonly, presence, selected, maximumlength, sequence, + block, displaytype, typeofdata, quickcreate, quickcreatesequence, info_type, helpinfo) + VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)", + Array($this->getModuleId(), $this->id, $this->column, $this->table, $this->generatedtype, + $this->uitype, $this->name, $this->label, $this->readonly, $this->presence, $this->selected, + $this->maximumlength, $this->sequence, $this->getBlockId(), $this->displaytype, $this->typeofdata, + $this->quickcreate, $this->quicksequence, $this->info_type, $this->helpinfo)); + + // Set the field status for mass-edit (if set) + $adb->pquery('UPDATE vtiger_field SET masseditable=? WHERE fieldid=?', Array($this->masseditable, $this->id)); + + Vtiger_Profile::initForField($this); + + if(!empty($this->columntype)) { + Vtiger_Utils::AddColumn($this->table, $this->column, $this->columntype); + } + + self::log("Creating Field $this->name ... DONE"); + self::log("Module language mapping for $this->label ... CHECK"); + } + + /** + * Update this field instance + * @access private + * @internal TODO + */ + function __update() { + self::log("Updating Field $this->name ... DONE"); + } + + /** + * Delete this field instance + * @access private + */ + function __delete() { + global $adb; + + Vtiger_Profile::deleteForField($this); + + $adb->pquery("DELETE FROM vtiger_field WHERE fieldid=?", Array($this->id)); + self::log("Deleteing Field $this->name ... DONE"); + } + + /** + * Get block id to which this field instance is associated + */ + function getBlockId() { + return $this->block->id; + } + + /** + * Get module id to which this field instance is associated + */ + function getModuleId() { + return $this->block->module->id; + } + + /** + * Get module name to which this field instance is associated + */ + function getModuleName() { + return $this->block->module->name; + } + + /** + * Get module instance to which this field instance is associated + */ + function getModuleInstance(){ + return $this->block->module; + } + + /** + * Save this field instance + * @param Vtiger_Block Instance of block to which this field should be added. + */ + function save($blockInstance=false) { + if($this->id) $this->__update(); + else $this->__create($blockInstance); + return $this->id; + } + + /** + * Delete this field instance + */ + function delete() { + $this->__delete(); + } + + /** + * Set Help Information for this instance. + * @param String Help text (content) + */ + function setHelpInfo($helptext) { + // Make sure to initialize the core tables first + $this->__handleVtigerCoreSchemaChanges(); + + global $adb; + $adb->pquery('UPDATE vtiger_field SET helpinfo=? WHERE fieldid=?', Array($helptext, $this->id)); + self::log("Updated help information of $this->name ... DONE"); + } + + /** + * Set Masseditable information for this instance. + * @param Integer Masseditable value + */ + function setMassEditable($value) { + global $adb; + $adb->pquery('UPDATE vtiger_field SET masseditable=? WHERE fieldid=?', Array($value, $this->id)); + self::log("Updated masseditable information of $this->name ... DONE"); + } + + /** + * Helper function to log messages + * @param String Message to log + * @param Boolean true appends linebreak, false to avoid it + * @access private + */ + static function log($message, $delim=true) { + Vtiger_Utils::Log($message, $delim); + } +} +?> diff --git a/oss/vtiger/trunk/vtlib/Vtiger/Filter.php b/oss/vtiger/trunk/vtlib/Vtiger/Filter.php new file mode 100644 index 00000000..dd327ec2 --- /dev/null +++ b/oss/vtiger/trunk/vtlib/Vtiger/Filter.php @@ -0,0 +1,291 @@ +getUniqueID('vtiger_customview'); + } + + /** + * Initialize this filter instance + * @param Vtiger_Module Instance of the module to which this filter is associated. + * @access private + */ + function initialize($valuemap, $moduleInstance=false) { + $this->id = $valuemap[cvid]; + $this->name= $valuemap[viewname]; + $this->module=$moduleInstance? $moduleInstance: Vtiger_Module::getInstance($valuemap[tabid]); + } + + /** + * Create this instance + * @param Vtiger_Module Instance of the module to which this filter should be associated with + * @access private + */ + function __create($moduleInstance) { + global $adb; + $this->module = $moduleInstance; + + $this->id = $this->__getUniqueId(); + $this->isdefault = ($this->isdefault===true||$this->isdefault=='true')?1:0; + $this->inmetrics = ($this->inmetrics===true||$this->inmetrics=='true')?1:0; + + $adb->pquery("INSERT INTO vtiger_customview(cvid,viewname,setdefault,setmetrics,entitytype) VALUES(?,?,?,?,?)", + Array($this->id, $this->name, $this->isdefault, $this->inmetrics, $this->module->name)); + + self::log("Creating Filter $this->name ... DONE"); + + // Filters are role based from 5.1.0 onwards + if(!$this->status) { + if(strtoupper(trim($this->name)) == 'ALL') $this->status = '0'; // Default + else $this->status = '3'; // Public + $adb->pquery("UPDATE vtiger_customview SET status=? WHERE cvid=?", Array($this->status, $this->id)); + + self::log("Setting Filter $this->name to status [$this->status] ... DONE"); + } + // END + + } + + /** + * Update this instance + * @access private + * @internal TODO + */ + function __update() { + self::log("Updating Filter $this->name ... DONE"); + } + + /** + * Delete this instance + * @access private + */ + function __delete() { + global $adb; + $adb->pquery("DELETE FROM vtiger_cvadvfilter WHERE cvid=?", Array($this->id)); + $adb->pquery("DELETE FROM vtiger_cvcolumnlist WHERE cvid=?", Array($this->id)); + $adb->pquery("DELETE FROM vtiger_customview WHERE cvid=?", Array($this->id)); + } + + /** + * Save this instance + * @param Vtiger_Module Instance of the module to use + */ + function save($moduleInstance=false) { + if($this->id) $this->__update(); + else $this->__create($moduleInstance); + return $this->id; + } + + /** + * Delete this instance + * @access private + */ + function delete() { + $this->__delete(); + } + + /** + * Get the column value to use in custom view tables. + * @param Vtiger_Field Instance of the field + * @access private + */ + function __getColumnValue($fieldInstance) { + $tod = split('~', $fieldInstance->typeofdata); + $displayinfo = $fieldInstance->getModuleName().'_'.str_replace(' ','_',$fieldInstance->label).':'.$tod[0]; + $cvcolvalue = "$fieldInstance->table:$fieldInstance->column:$fieldInstance->name:$displayinfo"; + return $cvcolvalue; + } + + /** + * Add the field to this filer instance + * @param Vtiger_Field Instance of the field + * @param Integer Index count to use + */ + function addField($fieldInstance, $index=0) { + global $adb; + + $cvcolvalue = $this->__getColumnValue($fieldInstance); + + $adb->pquery("UPDATE vtiger_cvcolumnlist SET columnindex=columnindex+1 WHERE cvid=? AND columnindex>=? ORDER BY columnindex DESC", + Array($this->id, $index)); + $adb->pquery("INSERT INTO vtiger_cvcolumnlist(cvid,columnindex,columnname) VALUES(?,?,?)", Array($this->id, $index, $cvcolvalue)); + + $this->log("Adding $fieldInstance->name to $this->name filter ... DONE"); + return $this; + } + + /** + * Add rule to this filter instance + * @param Vtiger_Field Instance of the field + * @param String One of [EQUALS, NOT_EQUALS, STARTS_WITH, ENDS_WITH, CONTAINS, DOES_NOT_CONTAINS, LESS_THAN, + * GREATER_THAN, LESS_OR_EQUAL, GREATER_OR_EQUAL] + * @param String Value to use for comparision + * @param Integer Index count to use + */ + function addRule($fieldInstance, $comparator, $comparevalue, $index=0) { + global $adb; + + if(empty($comparator)) return $this; + + $comparator = self::translateComparator($comparator); + $cvcolvalue = $this->__getColumnValue($fieldInstance); + + $adb->pquery("UPDATE vtiger_cvadvfilter set columnindex=columnindex+1 WHERE cvid=? AND columnindex>=? ORDER BY columnindex DESC", + Array($this->id, $index)); + $adb->pquery("INSERT INTO vtiger_cvadvfilter(cvid, columnindex, columnname, comparator, value) VALUES(?,?,?,?,?)", + Array($this->id, $index, $cvcolvalue, $comparator, $comparevalue)); + + Vtiger_Utils::Log("Adding Condition " . self::translateComparator($comparator,true) ." on $fieldInstance->name of $this->name filter ... DONE"); + + return $this; + } + + /** + * Translate comparator (condition) to long or short form. + * @access private + * @internal Used from Vtiger_PackageExport also + */ + static function translateComparator($value, $tolongform=false) { + $comparator = false; + if($tolongform) { + $comparator = strtolower($value); + if($comparator == 'e') $comparator = 'EQUALS'; + else if($comparator == 'n') $comparator = 'NOT_EQUALS'; + else if($comparator == 's') $comparator = 'STARTS_WITH'; + else if($comparator == 'ew') $comparator = 'ENDS_WITH'; + else if($comparator == 'c') $comparator = 'CONTAINS'; + else if($comparator == 'k') $comparator = 'DOES_NOT_CONTAINS'; + else if($comparator == 'l') $comparator = 'LESS_THAN'; + else if($comparator == 'g') $comparator = 'GREATER_THAN'; + else if($comparator == 'm') $comparator = 'LESS_OR_EQUAL'; + else if($comparator == 'h') $comparator = 'GREATER_OR_EQUAL'; + } else { + $comparator = strtoupper($value); + if($comparator == 'EQUALS') $comparator = 'e'; + else if($comparator == 'NOT_EQUALS') $comparator = 'n'; + else if($comparator == 'STARTS_WITH') $comparator = 's'; + else if($comparator == 'ENDS_WITH') $comparator = 'ew'; + else if($comparator == 'CONTAINS') $comparator = 'c'; + else if($comparator == 'DOES_NOT_CONTAINS') $comparator = 'k'; + else if($comparator == 'LESS_THAN') $comparator = 'l'; + else if($comparator == 'GREATER_THAN') $comparator = 'g'; + else if($comparator == 'LESS_OR_EQUAL') $comparator = 'm'; + else if($comparator == 'GREATER_OR_EQUAL') $comparator = 'h'; + } + return $comparator; + } + + /** + * Helper function to log messages + * @param String Message to log + * @param Boolean true appends linebreak, false to avoid it + * @access private + */ + static function log($message, $delim=true) { + Vtiger_Utils::Log($message, $delim); + } + + /** + * Get instance by filterid or filtername + * @param mixed filterid or filtername + * @param Vtiger_Module Instance of the module to use when filtername is used + */ + static function getInstance($value, $moduleInstance=false) { + global $adb; + $instance = false; + + $query = false; + $queryParams = false; + if(Vtiger_Utils::isNumber($value)) { + $query = "SELECT * FROM vtiger_customview WHERE cvid=?"; + $queryParams = Array($value); + } else { + $query = "SELECT * FROM vtiger_customview WHERE viewname=? AND entitytype=?"; + $queryParams = Array($value, $moduleInstance->name); + } + $result = $adb->pquery($query, $queryParams); + if($adb->num_rows($result)) { + $instance = new self(); + $instance->initialize($adb->fetch_array($result), $moduleInstance); + } + return $instance; + } + + /** + * Get all instances of filter for the module + * @param Vtiger_Module Instance of module + */ + static function getAllForModule($moduleInstance) { + global $adb; + $instances = false; + + $query = "SELECT * FROM vtiger_customview WHERE entitytype=?"; + $queryParams = Array($moduleInstance->name); + + $result = $adb->pquery($query, $queryParams); + for($index = 0; $index < $adb->num_rows($result); ++$index) { + $instance = new self(); + $instance->initialize($adb->fetch_array($result), $moduleInstance); + $instances[] = $instance; + } + return $instances; + } + + /** + * Delete filter associated for module + * @param Vtiger_Module Instance of module + */ + static function deleteForModule($moduleInstance) { + global $adb; + + $cvidres = $adb->pquery("SELECT cvid FROM vtiger_customview WHERE entitytype=?", Array($moduleInstance->name)); + if($adb->num_rows($cvidres)) { + $cvids = Array(); + for($index = 0; $index < $adb->num_rows($cvidres); ++$index) { + $cvids[] = $adb->query_result($cvidres, $index, 'cvid'); + } + if(!empty($cvids)) { + $adb->query("DELETE FROM vtiger_cvadvfilter WHERE cvid IN (" . implode(',', $cvids) . ")"); + $adb->query("DELETE FROM vtiger_cvcolumnlist WHERE cvid IN (" . implode(',', $cvids) . ")"); + $adb->query("DELETE FROM vtiger_customview WHERE cvid IN (" . implode(',', $cvids) . ")"); + } + } + } +} +?> diff --git a/oss/vtiger/trunk/vtlib/Vtiger/Language.php b/oss/vtiger/trunk/vtlib/Vtiger/Language.php new file mode 100644 index 00000000..dedc8d23 --- /dev/null +++ b/oss/vtiger/trunk/vtlib/Vtiger/Language.php @@ -0,0 +1,25 @@ + diff --git a/oss/vtiger/trunk/vtlib/Vtiger/LanguageExport.php b/oss/vtiger/trunk/vtlib/Vtiger/LanguageExport.php new file mode 100644 index 00000000..60237d9c --- /dev/null +++ b/oss/vtiger/trunk/vtlib/Vtiger/LanguageExport.php @@ -0,0 +1,131 @@ +getUniqueID(self::TABLENAME); + } + + /** + * Initialize Language Schema + * @access private + */ + static function __initSchema() { + $hastable = Vtiger_Utils::CheckTable(self::TABLENAME); + if(!$hastable) { + Vtiger_Utils::CreateTable( + self::TABLENAME, + '(id INT NOT NULL PRIMARY KEY, + name VARCHAR(50), prefix VARCHAR(10), label VARCHAR(30), lastupdated DATETIME, sequence INT, isdefault INT(1), active INT(1))', + true + ); + global $languages, $adb; + foreach($languages as $langkey=>$langlabel) { + $uniqueid = self::__getUniqueId(); + $adb->pquery('INSERT INTO '.self::TABLENAME.'(id,name,prefix,label,lastupdated,active) VALUES(?,?,?,?,?,?)', + Array($uniqueid, $langlabel,$langkey,$langlabel,date('Y-m-d H:i:s',time()), 1)); + } + } + } + + /** + * Register language pack information. + */ + static function register($prefix, $label, $name='', $isdefault=false, $isactive=true, $overrideCore=false) { + self::__initSchema(); + + $prefix = trim($prefix); + // We will not allow registering core language unless forced + if(strtolower($prefix) == 'en_us' && $overrideCore == false) return; + + $useisdefault = ($isdefault)? 1 : 0; + $useisactive = ($isactive)? 1 : 0; + + global $adb; + $checkres = $adb->pquery('SELECT * FROM '.self::TABLENAME.' WHERE prefix=?', Array($prefix)); + $datetime = date('Y-m-d H:i:s'); + if($adb->num_rows($checkres)) { + $id = $adb->query_result($checkres, 0, 'id'); + $adb->pquery('UPDATE '.self::TABLENAME.' set label=?, name=?, lastupdated=?, isdefault=?, active=? WHERE id=?', + Array($label, $name, $datetime, $useisdefault, $useisactive, $id)); + } else { + $uniqueid = self::__getUniqueId(); + $adb->pquery('INSERT INTO '.self::TABLENAME.' (id,name,prefix,label,lastupdated,isdefault,active) VALUES(?,?,?,?,?,?,?)', + Array($uniqueid, $name, $prefix, $label, $datetime, $useisdefault, $useisactive)); + } + self::log("Registering Language $label [$prefix] ... DONE"); + } + + /** + * De-Register language pack information + * @param String Language prefix like (de_de) etc + */ + static function deregister($prefix) { + $prefix = trim($prefix); + // We will not allow deregistering core language + if(strtolower($prefix) == 'en_us') return; + + self::__initSchema(); + + global $adb; + $checkres = $adb->pquery('DELETE FROM '.self::TABLENAME.' WHERE prefix=?', Array($prefix)); + self::log("Deregistering Language $prefix ... DONE"); + } + + /** + * Get all the language information + * @param Boolean true to include in-active languages also, false (default) + */ + static function getAll($includeInActive=false) { + global $adb; + $hastable = Vtiger_Utils::CheckTable(self::TABLENAME); + + $languageinfo = Array(); + + if($hastable) { + if($includeInActive) $result = $adb->query('SELECT * FROM '.self::TABLENAME); + else $result = $adb->query('SELECT * FROM '.self::TABLENAME . ' WHERE active=1'); + + for($index = 0; $index < $adb->num_rows($result); ++$index) { + $resultrow = $adb->fetch_array($result); + $prefix = $resultrow['prefix']; + $label = $resultrow['label']; + $languageinfo[$prefix] = $label; + } + } else { + global $languages; + foreach($languages as $prefix=>$label) { + $languageinfo[$prefix] = $label; + } + } + return $languageinfo; + } +} +?> diff --git a/oss/vtiger/trunk/vtlib/Vtiger/LanguageImport.php b/oss/vtiger/trunk/vtlib/Vtiger/LanguageImport.php new file mode 100644 index 00000000..a06f6e67 --- /dev/null +++ b/oss/vtiger/trunk/vtlib/Vtiger/LanguageImport.php @@ -0,0 +1,138 @@ +_modulexml->name; + } + + /** + * Initialize Import + * @access private + */ + function initImport($zipfile, $overwrite) { + $this->__initSchema(); + + $name = $this->getModuleNameFromZip($zipfile); + } + + /** + * Import Module from zip file + * @param String Zip file name + * @param Boolean True for overwriting existing module + */ + function import($zipfile, $overwrite=false) { + $this->initImport($zipfile, $overwrite); + + // Call module import function + $this->import_Language($zipfile); + } + + /** + * Update Module from zip file + * @param Object Instance of Language (to keep Module update API consistent) + * @param String Zip file name + * @param Boolean True for overwriting existing module + */ + function update($instance, $zipfile, $overwrite=true) { + $this->import($zipfile, $overwrite); + } + + /** + * Import Module + * @access private + */ + function import_Language($zipfile) { + $name = $this->_modulexml->name; + $prefix = $this->_modulexml->prefix; + $label = $this->_modulexml->label; + + self::log("Importing $label [$prefix] ... STARTED"); + $unzip = new Vtiger_Unzip($zipfile); + $filelist = $unzip->getList(); + + foreach($filelist as $filename=>$fileinfo) { + if(!$unzip->isdir($filename)) { + + if(strpos($filename, '/') === false) continue; + + $targetdir = substr($filename, 0, strripos($filename,'/')); + $targetfile = basename($filename); + + $prefixparts = split('_', $prefix); + + $dounzip = false; + if(is_dir($targetdir)) { + // Case handling for jscalendar + if(stripos($targetdir, 'jscalendar/lang') === 0 + && stripos($targetfile, "calendar-".$prefixparts[0].".js")===0) { + + if(file_exists("$targetdir/calendar-en.js")) { + $dounzip = true; + } + } + // Case handling for phpmailer + else if(stripos($targetdir, 'modules/Emails/language') === 0 + && stripos($targetfile, "phpmailer.lang-$prefix.php")===0) { + + if(file_exists("$targetdir/phpmailer.lang-en_us.php")) { + $dounzip = true; + } + } + // Handle javascript language file + else if(preg_match("/$prefix.lang.js/", $targetfile)) { + $corelangfile = "$targetdir/en_us.lang.js"; + if(file_exists($corelangfile)) { + $dounzip = true; + } + } + // Handle php language file + else if(preg_match("/$prefix.lang.php/", $targetfile)) { + $corelangfile = "$targetdir/en_us.lang.php"; + if(file_exists($corelangfile)) { + $dounzip = true; + } + } + } + + if($dounzip) { + if($unzip->unzip($filename, $filename) !== false) { + self::log("Copying file $filename ... DONE"); + } else { + self::log("Copying file $filename ... FAILED"); + } + } else { + self::log("Copying file $filename ... SKIPPED"); + } + } + } + if($unzip) $unzip->close(); + + self::register($prefix, $label, $name); + + self::log("Importing $label [$prefix] ... DONE"); + + return; + } +} +?> diff --git a/oss/vtiger/trunk/vtlib/Vtiger/Link.php b/oss/vtiger/trunk/vtlib/Vtiger/Link.php new file mode 100644 index 00000000..f9de0601 --- /dev/null +++ b/oss/vtiger/trunk/vtlib/Vtiger/Link.php @@ -0,0 +1,224 @@ +tabid = $valuemap['tabid']; + $this->linkid = $valuemap['linkid']; + $this->linktype=$valuemap['linktype']; + $this->linklabel=$valuemap['linklabel']; + $this->linkurl =decode_html($valuemap['linkurl']); + $this->linkicon =decode_html($valuemap['linkicon']); + $this->sequence =$valuemap['sequence']; + $this->status =$valuemap['status']; + } + + /** + * Get module name. + */ + function module() { + if(!empty($this->tabid)) { + return getTabModuleName($this->tabid); + } + return false; + } + + /** + * Get unique id for the insertion + */ + static function __getUniqueId() { + global $adb; + return $adb->getUniqueID('vtiger_links'); + } + + /** Cache (Record) the schema changes to improve performance */ + static $__cacheSchemaChanges = Array(); + + /** + * Initialize the schema (tables) + */ + static function __initSchema() { + if(empty(self::$__cacheSchemaChanges['vtiger_links'])) { + if(!Vtiger_Utils::CheckTable('vtiger_links')) { + Vtiger_Utils::CreateTable( + 'vtiger_links', + '(linkid INT NOT NULL PRIMARY KEY, + tabid INT, linktype VARCHAR(20), linklabel VARCHAR(30), linkurl VARCHAR(255), linkicon VARCHAR(100), sequence INT, status INT(1) NOT NULL DEFAULT 1)', + true); + Vtiger_Utils::ExecuteQuery( + 'CREATE INDEX link_tabidtype_idx on vtiger_links(tabid,linktype)'); + } + self::$__cacheSchemaChanges['vtiger_links'] = true; + } + } + + /** + * Add link given module + * @param Integer Module ID + * @param String Link Type (like DETAILVIEW). Useful for grouping based on pages. + * @param String Label to display + * @param String HREF value or URL to use for the link + * @param String ICON to use on the display + * @param Integer Order or sequence of displaying the link + */ + static function addLink($tabid, $type, $label, $url, $iconpath='',$sequence=0) { + global $adb; + self::__initSchema(); + $checkres = $adb->pquery('SELECT linkid FROM vtiger_links WHERE tabid=? AND linktype=? AND linkurl=? AND linkicon=? AND linklabel=?', + Array($tabid, $type, $url, $iconpath, $label)); + if(!$adb->num_rows($checkres)) { + $uniqueid = self::__getUniqueId(); + $adb->pquery('INSERT INTO vtiger_links (linkid,tabid,linktype,linklabel,linkurl,linkicon,sequence) VALUES(?,?,?,?,?,?,?)', + Array($uniqueid, $tabid, $type, $label, $url, $iconpath, $sequence)); + self::log("Adding Link ($type - $label) ... DONE"); + } + } + + /** + * Delete link of the module + * @param Integer Module ID + * @param String Link Type (like DETAILVIEW). Useful for grouping based on pages. + * @param String Display label + * @param String URL of link to lookup while deleting + */ + static function deleteLink($tabid, $type, $label, $url=false) { + global $adb; + self::__initSchema(); + if($url) { + $adb->pquery('DELETE FROM vtiger_links WHERE tabid=? AND linktype=? AND linklabel=? AND linkurl=?', + Array($tabid, $type, $label, $url)); + self::log("Deleting Link ($type - $label - $url) ... DONE"); + } else { + $adb->pquery('DELETE FROM vtiger_links WHERE tabid=? AND linktype=? AND linklabel=?', + Array($tabid, $type, $label)); + self::log("Deleting Link ($type - $label) ... DONE"); + } + } + + /** + * Delete all links related to module + * @param Integer Module ID. + */ + static function deleteAll($tabid) { + global $adb; + self::__initSchema(); + $adb->pquery('DELETE FROM vtiger_links WHERE tabid=?', Array($tabid)); + self::log("Deleting Links ... DONE"); + } + + /** + * Get all the links related to module + * @param Integer Module ID. + */ + static function getAll($tabid) { + return self::getAllByType($tabid); + } + + /** + * Get all the link related to module based on type + * @param Integer Module ID + * @param mixed String or List of types to select + * @param Map Key-Value pair to use for formating the link url + */ + static function getAllByType($tabid, $type=false, $parameters=false) { + global $adb; + self::__initSchema(); + + $multitype = false; + + if($type) { + // Multiple link type selection? + if(is_array($type)) { + $multitype = true; + if($tabid === self::IGNORE_MODULE) { + $result = $adb->pquery('SELECT * FROM vtiger_links WHERE linktype IN ('. + Vtiger_Utils::implodestr('?', count($type), ',') .')', + Array($adb->flatten_array($type))); + } else { + $result = $adb->pquery('SELECT * FROM vtiger_links WHERE tabid=? AND linktype IN ('. + Vtiger_Utils::implodestr('?', count($type), ',') .')', + Array($tabid, $adb->flatten_array($type))); + } + } else { + // Single link type selection + if($tabid === self::IGNORE_MODULE) { + $result = $adb->pquery('SELECT * FROM vtiger_links WHERE linktype=?', Array($type)); + } else { + $result = $adb->pquery('SELECT * FROM vtiger_links WHERE tabid=? AND linktype=?', Array($tabid, $type)); + } + } + } else { + $result = $adb->pquery('SELECT * FROM vtiger_links WHERE tabid=?', Array($tabid)); + } + + $strtemplate = new Vtiger_StringTemplate(); + if($parameters) { + foreach($parameters as $key=>$value) $strtemplate->assign($key, $value); + } + + $instances = Array(); + if($multitype) { + foreach($type as $t) $instances[$t] = Array(); + } + + while($row = $adb->fetch_array($result)){ + $instance = new self(); + $instance->initialize($row); + if($parameters) { + $instance->linkurl = $strtemplate->merge($instance->linkurl); + $instance->linkicon= $strtemplate->merge($instance->linkicon); + } + if($multitype) { + $instances[$instance->linktype][] = $instance; + } else { + $instances[] = $instance; + } + } + return $instances; + } + + /** + * Helper function to log messages + * @param String Message to log + * @param Boolean true appends linebreak, false to avoid it + * @access private + */ + static function log($message, $delimit=true) { + Vtiger_Utils::Log($message, $delimit); + } +} +?> diff --git a/oss/vtiger/trunk/vtlib/Vtiger/Mailer.php b/oss/vtiger/trunk/vtlib/Vtiger/Mailer.php new file mode 100644 index 00000000..d1218681 --- /dev/null +++ b/oss/vtiger/trunk/vtlib/Vtiger/Mailer.php @@ -0,0 +1,233 @@ +initialize(); + } + + /** + * Get the unique id for insertion + * @access private + */ + function __getUniqueId() { + global $adb; + return $adb->getUniqueID('vtiger_mailer_queue'); + } + + /** + * Initialize this instance + * @access private + */ + function initialize() { + $this->IsSMTP(); + + global $adb; + $result = $adb->pquery("SELECT * FROM vtiger_systems WHERE server_type=?", Array('email')); + if($adb->num_rows($result)) { + $this->Host = $adb->query_result($result, 0, 'server'); + $this->Username = $adb->query_result($result, 0, 'server_username'); + $this->Password = $adb->query_result($result, 0, 'server_password'); + $this->SMTPAuth = $adb->query_result($result, 0, 'smtp_auth'); + if(empty($this->SMTPAuth)) $this->SMTPAuth = false; + + $this->_serverConfigured = true; + } + } + + /** + * Reinitialize this instance for use + * @access private + */ + function reinitialize() { + $this->From = ''; + $this->FromName = ''; + $this->to = Array(); + $this->cc = Array(); + $this->bcc = Array(); + $this->ReplyTo = Array(); + $this->Body = ''; + $this->Subject =''; + $this->attachment = Array(); + } + + /** + * Initialize this instance using mail template + * @access private + */ + function initFromTemplate($emailtemplate) { + global $adb; + $result = $adb->pquery("SELECT * from vtiger_emailtemplates WHERE templatename=? AND foldername=?", + Array($emailtemplate, 'Public')); + if($adb->num_rows($result)) { + $this->IsHTML(true); + $usesubject = $adb->query_result($result, 0, 'subject'); + $usebody = decode_html($adb->query_result($result, 0, 'body')); + + $this->Subject = $usesubject; + $this->Body = $usebody; + return true; + } + return false; + } + + /** + * Configure sender information + */ + function ConfigSenderInfo($fromemail, $fromname='', $replyto='') { + if(empty($fromname)) $fromname = $fromemail; + + $this->From = $fromemail; + $this->FromName = $fromname; + $this->AddReplyTo($replyto); + } + + /** + * Overriding default send + */ + function Send($sync=false, $linktoid=false) { + if(!$this->_serverConfigured) return; + + if($sync) return parent::Send(); + + $this->__AddToQueue($linktoid); + return true; + } + + /** + * Send mail using the email template + * @param String Recipient email + * @param String Recipient name + * @param String vtiger CRM Email template name to use + */ + function SendTo($toemail, $toname='', $emailtemplate=false, $linktoid=false, $sync=false) { + if(empty($toname)) $toname = $toemail; + $this->AddAddress($toemail, $toname); + if($emailtemplate) $this->initFromTemplate($emailtemplate); + return $this->Send($sync, $linktoid); + } + + /** Mail Queue **/ + // Check if this instance is initialized. + var $_queueinitialized = false; + function __initializeQueue() { + if(!$this->_queueinitialized) { + if(!Vtiger_Utils::CheckTable('vtiger_mailer_queue')) { + Vtiger_Utils::CreateTable('vtiger_mailer_queue', + '(id INT NOT NULL PRIMARY KEY, + fromname VARCHAR(100), fromemail VARCHAR(100), + mailer VARCHAR(10), content_type VARCHAR(15), subject VARCHAR(999), body TEXT, relcrmid INT, + failed INT(1) NOT NULL DEFAULT 0, failreason VARCHAR(255))', + true); + } + if(!Vtiger_Utils::CheckTable('vtiger_mailer_queueinfo')) { + Vtiger_Utils::CreateTable('vtiger_mailer_queueinfo', + '(id INTEGER, name VARCHAR(100), email VARCHAR(100), type VARCHAR(7))', + true); + } + $this->_queueinitialized = true; + } + return true; + } + + /** + * Add this mail to queue + */ + function __AddToQueue($linktoid) { + if($this->__initializeQueue()) { + global $adb; + $uniqueid = self::__getUniqueId(); + $adb->pquery('INSERT INTO vtiger_mailer_queue(id,fromname,fromemail,content_type,subject,body,mailer,relcrmid) VALUES(?,?,?,?,?,?,?,?)', + Array($uniqueid, $this->FromName, $this->From, $this->ContentType, $this->Subject, $this->Body, $this->Mailer, $linktoid)); + $queueid = $adb->database->Insert_ID(); + foreach($this->to as $toinfo) { + if(empty($toinfo[0])) continue; + $adb->pquery('INSERT INTO vtiger_mailer_queueinfo(id, name, email, type) VALUES(?,?,?,?)', + Array($queueid, $toinfo[1], $toinfo[0], 'TO')); + } + foreach($this->cc as $ccinfo) { + if(empty($ccinfo[0])) continue; + $adb->pquery('INSERT INTO vtiger_mailer_queueinfo(id, name, email, type) VALUES(?,?,?,?)', + Array($queueid, $ccinfo[1], $ccinfo[0], 'CC')); + } + foreach($this->bcc as $bccinfo) { + if(empty($bccinfo[0])) continue; + $adb->pquery('INSERT INTO vtiger_mailer_queueinfo(id, name, email, type) VALUES(?,?,?,?)', + Array($queueid, $bccinfo[1], $bccinfo[0], 'BCC')); + } + foreach($this->ReplyTo as $rtoinfo) { + if(empty($rtoinfo[0])) continue; + $adb->pquery('INSERT INTO vtiger_mailer_queueinfo(id, name, email, type) VALUES(?,?,?,?)', + Array($queueid, $rtoinfo[1], $rtoinfo[0], 'RPLYTO')); + } + } + } + + /** + * Dispatch (send) email that was queued. + */ + static function dispatchQueue() { + global $adb; + if(!Vtiger_Utils::CheckTable('vtiger_mailer_queue')) return; + + $mailer = new self(); + $queue = $adb->query('SELECT * FROM vtiger_mailer_queue WHERE failed != 1'); + if($adb->num_rows($queue)) { + for($index = 0; $index < $adb->num_rows($queue); ++$index) { + $mailer->reinitialize(); + + $queue_record = $adb->fetch_array($queue, $index); + $queueid = $queue_record['id']; + $relcrmid= $queue_record['relcrmid']; + + $mailer->From = $queue_record['fromemail']; + $mailer->From = $queue_record['fromname']; + $mailer->Subject=$queue_record['subject']; + $mailer->Body = decode_html($queue_record['body']); + $mailer->Mailer=$queue_record['mailer']; + $mailer->ContentType = $queue_record['content_type']; + + $emails = $adb->pquery('SELECT * FROM vtiger_mailer_queueinfo WHERE id=?', Array($queueid)); + for($eidx = 0; $eidx < $adb->num_rows($emails); ++$eidx) { + $email_record = $adb->fetch_array($emails, $eidx); + if($email_record[type] == 'TO') $mailer->AddAddress($email_record[email], $email_record[name]); + else if($email_record[type] == 'CC')$mailer->AddCC($email_record[email], $email_record[name]); + else if($email_record[type] == 'BCC')$mailer->AddBCC($email_record[email], $email_record[name]); + else if($email_record[type] == 'RPLYTO')$mailer->AddReplyTo($email_record[email], $email_record[name]); + } + $sent = $mailer->Send(true); + if($sent) { + Vtiger_Event::trigger('vtiger.mailer.mailsent', $relcrmid); + $adb->pquery('DELETE FROM vtiger_mailer_queue WHERE id=?', Array($queueid)); + $adb->pquery('DELETE FROM vtiger_mailer_queueinfo WHERE id=?', Array($queueid)); + } else { + $adb->pquery('UPDATE vtiger_mailer_queueinfo SET failed=?, failreason=? WHERE id=?', Array(1, $mailer->ErrorInfo, $queueid)); + } + } + } + } +} +?> diff --git a/oss/vtiger/trunk/vtlib/Vtiger/Menu.php b/oss/vtiger/trunk/vtlib/Vtiger/Menu.php new file mode 100644 index 00000000..f034d5ba --- /dev/null +++ b/oss/vtiger/trunk/vtlib/Vtiger/Menu.php @@ -0,0 +1,142 @@ +id = $valuemap[parenttabid]; + $this->label = $valuemap[parenttab_label]; + $this->sequence = $valuemap[sequence]; + $this->visible = $valuemap[visible]; + } + + /** + * Get relation sequence to use + * @access private + */ + function __getNextRelSequence() { + global $adb; + $result = $adb->pquery("SELECT MAX(sequence) AS max_seq FROM vtiger_parenttabrel WHERE parenttabid=?", + Array($this->id)); + $maxseq = $adb->query_result($result, 0, 'max_seq'); + return ++$maxseq; + } + + /** + * Add module to this menu instance + * @param Vtiger_Module Instance of the module + */ + function addModule($moduleInstance) { + if($this->id) { + global $adb; + $relsequence = $this->__getNextRelSequence(); + $adb->pquery("INSERT INTO vtiger_parenttabrel (parenttabid,tabid,sequence) VALUES(?,?,?)", + Array($this->id, $moduleInstance->id, $relsequence)); + self::log("Added to menu $this->label ... DONE"); + } else { + self::log("Menu could not be found!"); + } + self::syncfile(); + } + + /** + * Remove module from this menu instance. + * @param Vtiger_Module Instance of the module + */ + function removeModule($moduleInstance) { + if(empty($moduleInstance) || empty($moduleInstance)) { + self::log("Module instance is not set!"); + return; + } + if($this->id) { + global $adb; + $adb->pquery("DELETE FROM vtiger_parenttabrel WHERE parenttabid = ? AND tabid = ?", + Array($this->id, $moduleInstance->id)); + self::log("Removed $moduleInstance->name from menu $this->label ... DONE"); + } else { + self::log("Menu could not be found!"); + } + self::syncfile(); + } + + /** + * Detach module from menu + * @param Vtiger_Module Instance of the module + */ + static function detachModule($moduleInstance) { + global $adb; + $adb->pquery("DELETE FROM vtiger_parenttabrel WHERE tabid=?", Array($moduleInstance->id)); + self::log("Detaching from menu ... DONE"); + self::syncfile(); + } + + /** + * Get instance of menu by label + * @param String Menu label + */ + static function getInstance($value) { + global $adb; + $query = false; + $instance = false; + if(Vtiger_Utils::isNumber($value)) { + $query = "SELECT * FROM vtiger_parenttab WHERE parenttabid=?"; + } else { + $query = "SELECT * FROM vtiger_parenttab WHERE parenttab_label=?"; + } + $result = $adb->pquery($query, Array($value)); + if($adb->num_rows($result)) { + $instance = new self(); + $instance->initialize($adb->fetch_array($result)); + } + return $instance; + } + + /** + * Helper function to log messages + * @param String Message to log + * @param Boolean true appends linebreak, false to avoid it + * @access private + */ + static function log($message, $delim=true) { + Vtiger_Utils::Log($message, $delim); + } + + /** + * Synchronize the menu information to flat file + * @access private + */ + static function syncfile() { + self::log("Updating parent_tabdata file ... STARTED"); + create_parenttab_data_file(); + self::log("Updating parent_tabdata file ... DONE"); + } +} +?> diff --git a/oss/vtiger/trunk/vtlib/Vtiger/Module.php b/oss/vtiger/trunk/vtlib/Vtiger/Module.php new file mode 100644 index 00000000..ad1a4692 --- /dev/null +++ b/oss/vtiger/trunk/vtlib/Vtiger/Module.php @@ -0,0 +1,193 @@ +getUniqueID('vtiger_relatedlists'); + } + + /** + * Get related list sequence to use + * @access private + */ + function __getNextRelatedListSequence() { + global $adb; + $max_sequence = 0; + $result = $adb->pquery("SELECT max(sequence) as maxsequence FROM vtiger_relatedlists WHERE tabid=?", Array($this->id)); + if($adb->num_rows($result)) $max_sequence = $adb->query_result($result, 0, 'maxsequence'); + return ++$max_sequence; + } + + /** + * Set related list information between other module + * @param Vtiger_Module Instance of target module with which relation should be setup + * @param String Label to display in related list (default is target module name) + * @param Array List of action button to show ('ADD', 'SELECT') + * @param String Callback function name of this module to use as handler + * + * @internal Creates table vtiger_crmentityrel if it does not exists + */ + function setRelatedList($moduleInstance, $label='', $actions=false, $function_name='get_related_list') { + global $adb; + + if(empty($moduleInstance)) return; + + Vtiger_Utils::CreateTable( + 'vtiger_crmentityrel', + '(crmid INT NOT NULL, module VARCHAR(100) NOT NULL, relcrmid INT NOT NULL, relmodule VARCHAR(100) NOT NULL)', + true + ); + + $relation_id = $this->__getRelatedListUniqueId(); + $sequence = $this->__getNextRelatedListSequence(); + $presence = 0; // 0 - Enabled, 1 - Disabled + + if(empty($label)) $label = $moduleInstance->name; + + // Allow ADD action of other module records (default) + if($actions === false) $actions = Array('ADD'); + + $useactions_text = $actions; + if(is_array($actions)) $useactions_text = implode(',', $actions); + $useactions_text = strtoupper($useactions_text); + + // Add column to vtiger_relatedlists to save extended actions + Vtiger_Utils::AddColumn('vtiger_relatedlists', 'actions', 'VARCHAR(50)'); + + $adb->pquery("INSERT INTO vtiger_relatedlists(relation_id,tabid,related_tabid,name,sequence,label,presence,actions) VALUES(?,?,?,?,?,?,?,?)", + Array($relation_id,$this->id,$moduleInstance->id,$function_name,$sequence,$label,$presence,$useactions_text)); + + self::log("Setting relation with $moduleInstance->name [$useactions_text] ... DONE"); + } + + /** + * Unset related list information that exists with other module + * @param Vtiger_Module Instance of target module with which relation should be setup + * @param String Label to display in related list (default is target module name) + * @param String Callback function name of this module to use as handler + */ + function unsetRelatedList($moduleInstance, $label='', $function_name='get_related_list') { + global $adb; + + if(empty($moduleInstance)) return; + + if(empty($label)) $label = $moduleInstance->name; + + $adb->pquery("DELETE FROM vtiger_relatedlists WHERE tabid=? AND related_tabid=? AND name=? AND label=?", + Array($this->id, $moduleInstance->id, $function_name, $label)); + + self::log("Unsetting relation with $moduleInstance->name ... DONE"); + } + + /** + * Add custom link for a module page + * @param String Type can be like 'DETAILVIEW', 'LISTVIEW' etc.. + * @param String Label to use for display + * @param String HREF value to use for generated link + * @param String Path to the image file (relative or absolute) + * @param Integer Sequence of appearance + * + * NOTE: $url can have variables like $MODULE (module for which link is associated), + * $RECORD (record on which link is dispalyed) + */ + function addLink($type, $label, $url, $iconpath='', $sequence=0) { + Vtiger_Link::addLink($this->id, $type, $label, $url, $iconpath, $sequence); + } + + /** + * Delete custom link of a module + * @param String Type can be like 'DETAILVIEW', 'LISTVIEW' etc.. + * @param String Display label to lookup + * @param String URL value to lookup + */ + function deleteLink($type, $label, $url=false) { + Vtiger_Link::deleteLink($this->id, $type, $label, $url); + } + + /** + * Get all the custom links related to this module. + */ + function getLinks() { + return Vtiger_Link::getAll($this->id); + } + + /** + * Initialize webservice setup for this module instance. + */ + function initWebservice() { + Vtiger_Webservice::initialize($this); + } + + /** + * Get instance by id or name + * @param mixed id or name of the module + */ + static function getInstance($value) { + global $adb; + $instance = false; + + $query = false; + if(Vtiger_Utils::isNumber($value)) { + $query = "SELECT * FROM vtiger_tab WHERE tabid=?"; + } else { + $query = "SELECT * FROM vtiger_tab WHERE name=?"; + } + $result = $adb->pquery($query, Array($value)); + if($adb->num_rows($result)) { + $instance = new self(); + $instance->initialize($adb->fetch_array($result)); + } + return $instance; + } + + /** + * Get instance of the module class. + * @param String Module name + */ + static function getClassInstance($modulename) { + if($modulename == 'Calendar') $modulename = 'Activity'; + + $instance = false; + $filepath = "modules/$modulename/$modulename.php"; + if(Vtiger_Utils::checkFileAccess($filepath, false)) { + include_once($filepath); + if(class_exists($modulename)) { + $instance = new $modulename(); + } + } + return $instance; + } + + /** + * Fire the event for the module (if vtlib_handler is defined) + */ + static function fireEvent($modulename, $event_type) { + $instance = self::getClassInstance((string)$modulename); + if($instance) { + if(method_exists($instance, 'vtlib_handler')) { + self::log("Invoking vtlib_handler for $event_type ...START"); + $instance->vtlib_handler((string)$modulename, (string)$event_type); + self::log("Invoking vtlib_handler for $event_type ...DONE"); + } + } + } +} +?> \ No newline at end of file diff --git a/oss/vtiger/trunk/vtlib/Vtiger/ModuleBasic.php b/oss/vtiger/trunk/vtlib/Vtiger/ModuleBasic.php new file mode 100644 index 00000000..1a29af0b --- /dev/null +++ b/oss/vtiger/trunk/vtlib/Vtiger/ModuleBasic.php @@ -0,0 +1,389 @@ +id = $valuemap['tabid']; + $this->name=$valuemap['name']; + $this->label=$valuemap['tablabel']; + $this->version=$valuemap['version']; + + $this->presence = $valuemap['presence']; + $this->ownedby = $valuemap['ownedby']; + $this->tabsequence = $valuemap['tabsequence']; + + $this->isentitytype = $valuemap['isentitytype']; + + if($this->isentitytype || $this->name == 'Users') { + // Initialize other details too + $this->initialize2(); + } + } + + /** + * Initialize more information of this instance + * @access private + */ + function initialize2() { + global $adb; + $result = $adb->pquery("SELECT tablename,entityidfield FROM vtiger_entityname WHERE tabid=?", + Array($this->id)); + if($adb->num_rows($result)) { + $this->basetable = $adb->query_result($result, 0, 'tablename'); + $this->basetableid=$adb->query_result($result, 0, 'entityidfield'); + } + } + + /** + * Get unique id for this instance + * @access private + */ + function __getUniqueId() { + global $adb; + $result = $adb->query("SELECT MAX(tabid) AS max_seq FROM vtiger_tab"); + $maxseq = $adb->query_result($result, 0, 'max_seq'); + return ++$maxseq; + } + + /** + * Get next sequence to use for this instance + * @access private + */ + function __getNextSequence() { + global $adb; + $result = $adb->query("SELECT MAX(tabsequence) AS max_tabseq FROM vtiger_tab"); + $maxtabseq = $adb->query_result($result, 0, 'max_tabseq'); + return ++$maxtabseq; + } + + /** + * Initialize vtiger schema changes. + * @access private + */ + function __handleVtigerCoreSchemaChanges() { + // Add version column to the table first + Vtiger_Utils::AddColumn('vtiger_tab', 'version', ' VARCHAR(10)'); + } + + /** + * Create this module instance + * @access private + */ + function __create() { + global $adb; + + self::log("Creating Module $this->name ... STARTED"); + + $this->id = $this->__getUniqueId(); + if(!$this->tabsequence) $this->tabsequence = $this->__getNextSequence(); + if(!$this->label) $this->label = $this->name; + + $customized = 1; // To indicate this is a Custom Module + + $this->__handleVtigerCoreSchemaChanges(); + + $adb->pquery("INSERT INTO vtiger_tab (tabid,name,presence,tabsequence,tablabel,modifiedby, + modifiedtime,customized,ownedby,version) VALUES (?,?,?,?,?,?,?,?,?,?)", + Array($this->id, $this->name, $this->presence, $this->tabsequence, $this->label, NULL, NULL, $customized, $this->ownedby, $this->version)); + + $useisentitytype = $this->isentitytype? 1 : 0; + $adb->pquery('UPDATE vtiger_tab set isentitytype=? WHERE tabid=?',Array($useisentitytype, $this->id)); + + Vtiger_Profile::initForModule($this); + + self::syncfile(); + + if($this->isentitytype) { + Vtiger_Access::initSharing($this); + } + + self::log("Creating Module $this->name ... DONE"); + } + + /** + * Update this instance + * @access private + */ + function __update() { + self::log("Updating Module $this->name ... DONE"); + } + + /** + * Delete this instance + * @access private + */ + function __delete() { + Vtiger_Module::fireEvent($this->name, + Vtiger_Module::EVENT_MODULE_PREUNINSTALL); + + global $adb; + if($this->isentitytype) { + $this->unsetEntityIdentifier(); + $this->deleteRelatedLists(); + } + + $adb->pquery("DELETE FROM vtiger_tab WHERE tabid=?", Array($this->id)); + self::log("Deleting Module $this->name ... DONE"); + } + + /** + * Update module version information + * @access private + */ + function __updateVersion($newversion) { + $this->__handleVtigerCoreSchemaChanges(); + global $adb; + $adb->pquery("UPDATE vtiger_tab SET version=? WHERE tabid=?", Array($newversion, $this->id)); + $this->version = $newversion; + self::log("Updating version to $newversion ... DONE"); + } + + /** + * Save this instance + */ + function save() { + if($this->id) $this->__update(); + else $this->__create(); + return $this->id; + } + + /** + * Delete this instance + */ + function delete() { + if($this->isentitytype) { + Vtiger_Access::deleteSharing($this); + Vtiger_Access::deleteTools($this); + Vtiger_Filter::deleteForModule($this); + Vtiger_Block::deleteForModule($this); + } + $this->__delete(); + Vtiger_Profile::deleteForModule($this); + Vtiger_Link::deleteAll($this->id); + Vtiger_Menu::detachModule($this); + self::syncfile(); + } + + /** + * Initialize table required for the module + * @param String Base table name (default modulename in lowercase) + * @param String Base table column (default modulenameid in lowercase) + * + * Creates basetable, customtable, grouptable
+ * customtable name is basetable + 'cf'
+ * grouptable name is basetable + 'grouprel'
+ */ + function initTables($basetable=false, $basetableid=false) { + $this->basetable = $basetable; + $this->basetableid=$basetableid; + + // Initialize tablename and index column names + $lcasemodname = strtolower($this->name); + if(!$this->basetable) $this->basetable = "vtiger_$lcasemodname"; + if(!$this->basetableid)$this->basetableid=$lcasemodname . "id"; + + if(!$this->customtable)$this->customtable = $this->basetable . "cf"; + if(!$this->grouptable)$this->grouptable = $this->basetable."grouprel"; + + Vtiger_Utils::CreateTable($this->basetable,"($this->basetableid INT)",true); + Vtiger_Utils::CreateTable($this->customtable, + "($this->basetableid INT PRIMARY KEY)", true); + if(Vtiger_Version::check('5.0.4', '<=')) { + Vtiger_Utils::CreateTable($this->grouptable, + "($this->basetableid INT PRIMARY KEY, groupname varchar(100))",true); + } + } + + /** + * Set entity identifier field for this module + * @param Vtiger_Field Instance of field to use + */ + function setEntityIdentifier($fieldInstance) { + global $adb; + + if($this->basetableid) { + if(!$this->entityidfield) $this->entityidfield = $this->basetableid; + if(!$this->entityidcolumn)$this->entityidcolumn= $this->basetableid; + } + if($this->entityidfield && $this->entityidcolumn) { + $adb->pquery("INSERT INTO vtiger_entityname(tabid, modulename, tablename, fieldname, entityidfield, entityidcolumn) VALUES(?,?,?,?,?,?)", + Array($this->id, $this->name, $fieldInstance->table, $fieldInstance->name, $this->entityidfield, $this->entityidcolumn)); + self::log("Setting entity identifier ... DONE"); + } + } + + /** + * Unset entity identifier information + */ + function unsetEntityIdentifier() { + global $adb; + $adb->pquery("DELETE FROM vtiger_entityname WHERE tabid=?", Array($this->id)); + self::log("Unsetting entity identifier ... DONE"); + } + + /** + * Delete related lists information + */ + function deleteRelatedLists() { + global $adb; + $adb->pquery("DELETE FROM vtiger_relatedlists WHERE tabid=?", Array($this->id)); + self::log("Deleting related lists ... DONE"); + } + + /** + * Configure default sharing access for the module + * @param String Permission text should be one of ['Public_ReadWriteDelete', 'Public_ReadOnly', 'Public_ReadWrite', 'Private'] + */ + function setDefaultSharing($permission_text='Public_ReadWriteDelete') { + Vtiger_Access::setDefaultSharing($this, $permission_text); + } + + /** + * Allow module sharing control + */ + function allowSharing() { + Vtiger_Access::allowSharing($this, true); + } + /** + * Disallow module sharing control + */ + function disallowSharing() { + Vtiger_Access::allowSharing($this, false); + } + + /** + * Enable tools for this module + * @param mixed String or Array with value ['Import', 'Export', 'Merge'] + */ + function enableTools($tools) { + if(is_string($tools)) { + $tools = Array(0 => $tools); + } + + foreach($tools as $tool) { + Vtiger_Access::updateTool($this, $tool, true); + } + } + + /** + * Disable tools for this module + * @param mixed String or Array with value ['Import', 'Export', 'Merge'] + */ + function disableTools($tools) { + if(is_string($tools)) { + $tools = Array(0 => $tools); + } + foreach($tools as $tool) { + Vtiger_Access::updateTool($this, $tool, false); + } + } + + /** + * Add block to this module + * @param Vtiger_Block Instance of block to add + */ + function addBlock($blockInstance) { + $blockInstance->save($this); + return $this; + } + + /** + * Add filter to this module + * @param Vtiger_Filter Instance of filter to add + */ + function addFilter($filterInstance) { + $filterInstance->save($this); + return $this; + } + + /** + * Get all the fields of the module or block + * @param Vtiger_Block Instance of block to use to get fields, false to get all the block fields + */ + function getFields($blockInstance=false) { + $fields = false; + if($blockInstance) $fields = Vtiger_Field::getAllForBlock($blockInstance, $this); + else $fields = Vtiger_Field::getAllForModule($this); + return $fields; + } + + /** + * Helper function to log messages + * @param String Message to log + * @param Boolean true appends linebreak, false to avoid it + * @access private + */ + static function log($message, $delimit=true) { + Vtiger_Utils::Log($message, $delimit); + } + + /** + * Synchronize the menu information to flat file + * @access private + */ + static function syncfile() { + self::log("Updating tabdata file ... ", false); + create_tab_data_file(); + self::log("DONE"); + } +} +?> diff --git a/oss/vtiger/trunk/vtlib/Vtiger/Net/Client.php b/oss/vtiger/trunk/vtlib/Vtiger/Net/Client.php new file mode 100644 index 00000000..34683f34 --- /dev/null +++ b/oss/vtiger/trunk/vtlib/Vtiger/Net/Client.php @@ -0,0 +1,117 @@ +setURL($url); + } + + /** + * Set another url for this instance + * @param String URL to use go forward + */ + function setURL($url) { + $this->url = $url; + $this->client = new HTTP_Request(); + $this->response = false; + } + + /** + * Set custom HTTP Headers + * @param Map HTTP Header and Value Pairs + */ + function setHeaders($values) { + foreach($values as $key=>$value) { + $this->client->addHeader($key, $value); + } + } + + /** + * Perform a GET request + * @param Map key-value pair or false + * @param Integer timeout value + */ + function doGet($params=false, $timeout=null) { + if($timeout) $this->client->_timeout = $timeout; + $this->client->setURL($this->url); + $this->client->setMethod(HTTP_REQUEST_METHOD_GET); + + if($params) { + foreach($params as $key=>$value) + $this->client->addQueryString($key, $value); + } + $this->response = $this->client->sendRequest(); + + $content = false; + if(!$this->wasError()) { + $content = $this->client->getResponseBody(); + } + $this->disconnect(); + return $content; + } + + /** + * Perform a POST request + * @param Map key-value pair or false + * @param Integer timeout value + */ + function doPost($params=false, $timeout=null) { + if($timeout) $this->client->_timeout = $timeout; + $this->client->setURL($this->url); + $this->client->setMethod(HTTP_REQUEST_METHOD_POST); + + if($params) { + if(is_string($params)) $this->client->addRawPostData($params); + else { + foreach($params as $key=>$value) + $this->client->addPostData($key, $value); + } + } + $this->response = $this->client->sendRequest(); + + $content = false; + if(!$this->wasError()) { + $content = $this->client->getResponseBody(); + } + $this->disconnect(); + + return $content; + } + + /** + * Did last request resulted in error? + */ + function wasError() { + return PEAR::isError($this->response); + } + + /** + * Disconnect this instance + */ + function disconnect() { + $this->client->disconnect(); + } +} +?> diff --git a/oss/vtiger/trunk/vtlib/Vtiger/Package.php b/oss/vtiger/trunk/vtlib/Vtiger/Package.php new file mode 100644 index 00000000..4ec88da1 --- /dev/null +++ b/oss/vtiger/trunk/vtlib/Vtiger/Package.php @@ -0,0 +1,25 @@ + diff --git a/oss/vtiger/trunk/vtlib/Vtiger/PackageExport.php b/oss/vtiger/trunk/vtlib/Vtiger/PackageExport.php new file mode 100644 index 00000000..8ea835dd --- /dev/null +++ b/oss/vtiger/trunk/vtlib/Vtiger/PackageExport.php @@ -0,0 +1,606 @@ +_export_tmpdir) === FALSE) { + mkdir($this->_export_tmpdir); + } + } + + /** Output Handlers */ + + /** @access private */ + function openNode($node,$delimiter="\n") { + $this->__write("<$node>$delimiter"); + } + /** @access private */ + function closeNode($node,$delimiter="\n") { + $this->__write("$delimiter"); + } + /** @access private */ + function outputNode($value, $node='') { + if($node != '') $this->openNode($node,''); + $this->__write($value); + if($node != '') $this->closeNode($node); + } + /** @access private */ + function __write($value) { + fwrite($this->_export_modulexml_file, $value); + } + + /** + * Set the module.xml file path for this export and + * return its temporary path. + * @access private + */ + function __getManifestFilePath() { + if(empty($this->_export_modulexml_filename)) { + // Set the module xml filename to be written for exporting. + $this->_export_modulexml_filename = "manifest-".time().".xml"; + } + return "$this->_export_tmpdir/$this->_export_modulexml_filename"; + } + + /** + * Initialize Export + * @access private + */ + function __initExport($module, $moduleInstance) { + if($moduleInstance->isentitytype) { + // We will be including the file, so do a security check. + Vtiger_Utils::checkFileAccess("modules/$module/$module.php"); + } + $this->_export_modulexml_file = fopen($this->__getManifestFilePath(), 'w'); + $this->__write("\n"); + } + + /** + * Post export work. + * @access private + */ + function __finishExport() { + if(!empty($this->_export_modulexml_file)) { + fclose($this->_export_modulexml_file); + $this->_export_modulexml_file = null; + } + } + + /** + * Clean up the temporary files created. + * @access private + */ + function __cleanupExport() { + if(!empty($this->_export_modulexml_filename)) { + unlink($this->__getManifestFilePath()); + } + } + + /** + * Export Module as a zip file. + * @param Vtiger_Module Instance of module + * @param Path Output directory path + * @param String Zipfilename to use + * @param Boolean True for sending the output as download + */ + function export($moduleInstance, $todir='', $zipfilename='', $directDownload=false) { + + $module = $moduleInstance->name; + + $this->__initExport($module, $moduleInstance); + + // Call module export function + $this->export_Module($moduleInstance); + + $this->__finishExport(); + + // Export as Zip + if($zipfilename == '') $zipfilename = "$module-" . date('YmdHis') . ".zip"; + $zipfilename = "$this->_export_tmpdir/$zipfilename"; + + $zip = new Vtiger_Zip($zipfilename); + // Add manifest file + $zip->addFile($this->__getManifestFilePath(), "manifest.xml"); + // Copy module directory + $zip->copyDirectoryFromDisk("modules/$module"); + // Copy templates directory of the module (if any) + if(is_dir("Smarty/templates/modules/$module")) + $zip->copyDirectoryFromDisk("Smarty/templates/modules/$module", "templates"); + // Copy cron files of the module (if any) + if(is_dir("cron/modules/$module")) + $zip->copyDirectoryFromDisk("cron/modules/$module", "cron"); + + $zip->save(); + + if($directDownload) { + $zip->forceDownload($zipfilename); + unlink($zipfilename); + } + $this->__cleanupExport(); + } + + /** + * Export vtiger dependencies + * @access private + */ + function export_Dependencies() { + global $vtiger_current_version; + $this->openNode('dependencies'); + $this->outputNode($vtiger_current_version, 'vtiger_version'); + $this->closeNode('dependencies'); + } + + /** + * Export Module Handler + * @access private + */ + function export_Module($moduleInstance) { + global $adb; + + $moduleid = $moduleInstance->id; + + $sqlresult = $adb->query("SELECT * FROM vtiger_parenttabrel WHERE tabid = $moduleid"); + $parenttabid = $adb->query_result($sqlresult, 0, 'parenttabid'); + $menu = Vtiger_Menu::getInstance($parenttabid); + $parent_name = $menu->label; + + $sqlresult = $adb->query("SELECT * FROM vtiger_tab WHERE tabid = $moduleid"); + $tabresultrow = $adb->fetch_array($sqlresult); + + $tabname = $tabresultrow['name']; + $tablabel= $tabresultrow['tablabel']; + $tabversion = isset($tabresultrow['version'])? $tabresultrow['version'] : false; + + $this->openNode('module'); + $this->outputNode(date('Y-m-d H:i:s'),'exporttime'); + $this->outputNode($tabname, 'name'); + $this->outputNode($tablabel, 'label'); + $this->outputNode($parent_name, 'parent'); + + if(!$moduleInstance->isentitytype) { + $this->outputNode('extension', 'type'); + } + + if($tabversion) { + $this->outputNode($tabversion, 'version'); + } + + // Export dependency information + $this->export_Dependencies(); + + // Export module tables + $this->export_Tables($moduleInstance); + + // Export module blocks + $this->export_Blocks($moduleInstance); + + // Export module filters + $this->export_CustomViews($moduleInstance); + + // Export Sharing Access + $this->export_SharingAccess($moduleInstance); + + // Export Events + $this->export_Events($moduleInstance); + + // Export Actions + $this->export_Actions($moduleInstance); + + // Export Related Lists + $this->export_RelatedLists($moduleInstance); + + // Export Custom Links + $this->export_CustomLinks($moduleInstance); + + $this->closeNode('module'); + } + + /** + * Export module base and related tables + * @access private + */ + function export_Tables($moduleInstance) { + + $_exportedTables = Array(); + + $modulename = $moduleInstance->name; + + $this->openNode('tables'); + + if($moduleInstance->isentitytype) { + $focus = CRMEntity::getInstance($modulename); + + // Setup required module variables which is need for vtlib API's + vtlib_setup_modulevars($modulename, $focus); + + $tables = Array ($focus->table_name); + if(!empty($focus->groupTable)) $tables[] = $focus->groupTable[0]; + if(!empty($focus->customFieldTable)) $tables[] = $focus->customFieldTable[0]; + + foreach($tables as $table) { + $this->openNode('table'); + $this->outputNode($table, 'name'); + $this->outputNode('', 'sql'); + $this->closeNode('table'); + + $_exportedTables[] = $table; + } + + } + + // Now export table information recorded in schema file + if(file_exists("modules/$modulename/schema.xml")) { + $schema = simplexml_load_file("modules/$modulename/schema.xml"); + + if(!empty($schema->tables) && !empty($schema->tables->table)) { + foreach($schema->tables->table as $tablenode) { + $table = trim($tablenode->name); + if(!in_array($table,$_exportedTables)) { + $this->openNode('table'); + $this->outputNode($table, 'name'); + $this->outputNode('', 'sql'); + $this->closeNode('table'); + + $_exportedTables[] = $table; + } + } + } + } + $this->closeNode('tables'); + } + + /** + * Export module blocks with its related fields + * @access private + */ + function export_Blocks($moduleInstance) { + global $adb; + $sqlresult = $adb->pquery("SELECT * FROM vtiger_blocks WHERE tabid = ?", Array($moduleInstance->id)); + $resultrows= $adb->num_rows($sqlresult); + + if(empty($resultrows)) return; + + $this->openNode('blocks'); + for($index = 0; $index < $resultrows; ++$index) { + $blockid = $adb->query_result($sqlresult, $index, 'blockid'); + $blocklabel = $adb->query_result($sqlresult, $index, 'blocklabel'); + + $this->openNode('block'); + $this->outputNode($blocklabel, 'label'); + // Export fields associated with the block + $this->export_Fields($moduleInstance, $blockid); + $this->closeNode('block'); + } + $this->closeNode('blocks'); + } + + /** + * Export fields related to a module block + * @access private + */ + function export_Fields($moduleInstance, $blockid) { + global $adb; + + $fieldresult = $adb->pquery("SELECT * FROM vtiger_field WHERE tabid=? AND block=?", Array($moduleInstance->id, $blockid)); + $fieldcount = $adb->num_rows($fieldresult); + + if(empty($fieldcount)) return; + + $entityresult = $adb->pquery("SELECT * FROM vtiger_entityname WHERE tabid=?", Array($moduleInstance->id)); + $entity_fieldname = $adb->query_result($entityresult, 0, 'fieldname'); + + $this->openNode('fields'); + for($index = 0; $index < $fieldcount; ++$index) { + $this->openNode('field'); + $fieldresultrow = $adb->fetch_row($fieldresult); + + $fieldname = $fieldresultrow['fieldname']; + $uitype = $fieldresultrow['uitype']; + $fieldid = $fieldresultrow['fieldid']; + + $this->outputNode($fieldname, 'fieldname'); + $this->outputNode($uitype, 'uitype'); + $this->outputNode($fieldresultrow['columnname'],'columnname'); + $this->outputNode($fieldresultrow['tablename'], 'tablename'); + $this->outputNode($fieldresultrow['generatedtype'], 'generatedtype'); + $this->outputNode($fieldresultrow['fieldlabel'], 'fieldlabel'); + $this->outputNode($fieldresultrow['readonly'], 'readonly'); + $this->outputNode($fieldresultrow['presence'], 'presence'); + $this->outputNode($fieldresultrow['selected'], 'selected'); + $this->outputNode($fieldresultrow['sequence'], 'sequence'); + $this->outputNode($fieldresultrow['maximumlength'], 'maximumlength'); + $this->outputNode($fieldresultrow['typeofdata'], 'typeofdata'); + $this->outputNode($fieldresultrow['quickcreate'], 'quickcreate'); + $this->outputNode($fieldresultrow['quickcreatesequence'], 'quickcreatesequence'); + $this->outputNode($fieldresultrow['displaytype'], 'displaytype'); + $this->outputNode($fieldresultrow['info_type'], 'info_type'); + $this->outputNode('', 'helpinfo'); + if(isset($fieldresultrow['masseditable'])) { + $this->outputNode($fieldresultrow['masseditable'], 'masseditable'); + } + + // Export Entity Identifier Information + if($fieldname == $entity_fieldname) { + $this->openNode('entityidentifier'); + $this->outputNode($adb->query_result($entityresult, 0, 'entityidfield'), 'entityidfield'); + $this->outputNode($adb->query_result($entityresult, 0, 'entityidcolumn'), 'entityidcolumn'); + $this->closeNode('entityidentifier'); + } + + // Export picklist values for picklist fields + if($uitype == '15' || $uitype == '16' || $uitype == '111' || $uitype == '33' || $uitype == '55') { + + if($uitype == '16') { + $picklistvalues = vtlib_getPicklistValues($fieldname); + } else { + $picklistvalues = vtlib_getPicklistValues_AccessibleToAll($fieldname); + } + $this->openNode('picklistvalues'); + foreach($picklistvalues as $picklistvalue) { + $this->outputNode($picklistvalue, 'picklistvalue'); + } + $this->closeNode('picklistvalues'); + } + + // Export field to module relations + if($uitype == '10') { + $relatedmodres = $adb->pquery("SELECT * FROM vtiger_fieldmodulerel WHERE fieldid=?", Array($fieldid)); + $relatedmodcount = $adb->num_rows($relatedmodres); + if($relatedmodcount) { + $this->openNode('relatedmodules'); + for($relmodidx = 0; $relmodidx < $relatedmodcount; ++$relmodidx) { + $this->outputNode($adb->query_result($relatedmodres, $relmodidx, 'relmodule'), 'relatedmodule'); + } + $this->closeNode('relatedmodules'); + } + } + + $this->closeNode('field'); + + } + $this->closeNode('fields'); + } + + /** + * Export Custom views of the module + * @access private + */ + function export_CustomViews($moduleInstance) { + global $adb; + + $customviewres = $adb->pquery("SELECT * FROM vtiger_customview WHERE entitytype = ?", Array($moduleInstance->name)); + $customviewcount=$adb->num_rows($customviewres); + + if(empty($customviewcount)) return; + + $this->openNode('customviews'); + for($cvindex = 0; $cvindex < $customviewcount; ++$cvindex) { + + $cvid = $adb->query_result($customviewres, $cvindex, 'cvid'); + + $cvcolumnres = $adb->query("SELECT * FROM vtiger_cvcolumnlist WHERE cvid=$cvid"); + $cvcolumncount=$adb->num_rows($cvcolumnres); + + $this->openNode('customview'); + + $setdefault = $adb->query_result($customviewres, $cvindex, 'setdefault'); + $setdefault = ($setdefault == 1)? 'true' : 'false'; + + $setmetrics = $adb->query_result($customviewres, $cvindex, 'setmetrics'); + $setmetrics = ($setmetrics == 1)? 'true' : 'false'; + + $this->outputNode($adb->query_result($customviewres, $cvindex, 'viewname'), 'viewname'); + $this->outputNode($setdefault, 'setdefault'); + $this->outputNode($setmetrics, 'setmetrics'); + + $this->openNode('fields'); + for($index = 0; $index < $cvcolumncount; ++$index) { + $cvcolumnindex = $adb->query_result($cvcolumnres, $index, 'columnindex'); + $cvcolumnname = $adb->query_result($cvcolumnres, $index, 'columnname'); + $cvcolumnnames= explode(':', $cvcolumnname); + $cvfieldname = $cvcolumnnames[2]; + + $this->openNode('field'); + $this->outputNode($cvfieldname, 'fieldname'); + $this->outputNode($cvcolumnindex,'columnindex'); + + $cvcolumnruleres = $adb->pquery("SELECT * FROM vtiger_cvadvfilter WHERE cvid=? AND columnname=?", + Array($cvid, $cvcolumnname)); + $cvcolumnrulecount = $adb->num_rows($cvcolumnruleres); + + if($cvcolumnrulecount) { + $this->openNode('rules'); + for($rindex = 0; $rindex < $cvcolumnrulecount; ++$rindex) { + $cvcolumnruleindex = $adb->query_result($cvcolumnruleres, $rindex, 'columnindex'); + $cvcolumnrulecomp = $adb->query_result($cvcolumnruleres, $rindex, 'comparator'); + $cvcolumnrulevalue = $adb->query_result($cvcolumnruleres, $rindex, 'value'); + $cvcolumnrulecomp = Vtiger_Filter::translateComparator($cvcolumnrulecomp, true); + + $this->openNode('rule'); + $this->outputNode($cvcolumnruleindex, 'columnindex'); + $this->outputNode($cvcolumnrulecomp, 'comparator'); + $this->outputNode($cvcolumnrulevalue, 'value'); + $this->closeNode('rule'); + + } + $this->closeNode('rules'); + } + + $this->closeNode('field'); + } + $this->closeNode('fields'); + + $this->closeNode('customview'); + } + $this->closeNode('customviews'); + } + + /** + * Export Sharing Access of the module + * @access private + */ + function export_SharingAccess($moduleInstance) { + global $adb; + + $deforgshare = $adb->pquery("SELECT * FROM vtiger_def_org_share WHERE tabid=?", Array($moduleInstance->id)); + $deforgshareCount = $adb->num_rows($deforgshare); + + if(empty($deforgshareCount)) return; + + $this->openNode('sharingaccess'); + if($deforgshareCount) { + for($index = 0; $index < $deforgshareCount; ++$index) { + $permission = $adb->query_result($deforgshare, $index, 'permission'); + $permissiontext = ''; + if($permission == '0') $permissiontext = 'public_readonly'; + if($permission == '1') $permissiontext = 'public_readwrite'; + if($permission == '2') $permissiontext = 'public_readwritedelete'; + if($permission == '3') $permissiontext = 'private'; + + $this->outputNode($permissiontext, 'default'); + } + } + $this->closeNode('sharingaccess'); + } + + /** + * Export Events of the module + * @access private + */ + function export_Events($moduleInstance) { + $events = Vtiger_Event::getAll($moduleInstance); + if(!$events) return; + + $this->openNode('events'); + foreach($events as $event) { + $this->openNode('event'); + $this->outputNode($event->eventname, 'eventname'); + $this->outputNode('classname.']]>', 'classname'); + $this->outputNode('filename.']]>', 'filename'); + $this->outputNode('condition.']]>', 'condition'); + $this->closeNode('event'); + } + $this->closeNode('events'); + } + + /** + * Export actions (tools) associated with module. + * TODO: Need to pickup values based on status for all user (profile) + * @access private + */ + function export_Actions($moduleInstance) { + + if(!$moduleInstance->isentitytype) return; + + global $adb; + $result = $adb->pquery('SELECT distinct(actionname) FROM vtiger_profile2utility, vtiger_actionmapping + WHERE vtiger_profile2utility.activityid=vtiger_actionmapping.actionid and tabid=?', Array($moduleInstance->id)); + + if($adb->num_rows($result)) { + $this->openNode('actions'); + while($resultrow = $adb->fetch_array($result)) { + $this->openNode('action'); + $this->outputNode('', 'name'); + $this->outputNode('enabled', 'status'); + $this->closeNode('action'); + } + $this->closeNode('actions'); + } + } + + /** + * Export related lists associated with module. + * @access private + */ + function export_RelatedLists($moduleInstance) { + + if(!$moduleInstance->isentitytype) return; + + global $adb; + $result = $adb->pquery("SELECT * FROM vtiger_relatedlists WHERE tabid = ?", Array($moduleInstance->id)); + if($adb->num_rows($result)) { + $this->openNode('relatedlists'); + + for($index = 0; $index < $adb->num_rows($result); ++$index) { + $row = $adb->fetch_array($result); + $this->openNode('relatedlist'); + + $this->outputNode($row['name'], 'function'); + $this->outputNode($row['label'], 'label'); + $this->outputNode($row['sequence'], 'sequence'); + $this->outputNode($row['presence'], 'presence'); + + $action_text = $row['actions']; + if(!empty($action_text)) { + $this->openNode('actions'); + $actions = explode(',', $action_text); + foreach($actions as $action) { + $this->outputNode($action, 'action'); + } + $this->closeNode('actions'); + } + + $relModuleInstance = Vtiger_Module::getInstance($row['related_tabid']); + $this->outputNode($relModuleInstance->name, 'relatedmodule'); + + $this->closeNode('relatedlist'); + } + + $this->closeNode('relatedlists'); + } + } + + /** + * Export custom links of the module. + * @access private + */ + function export_CustomLinks($moduleInstance) { + $customlinks = $moduleInstance->getLinks(); + if(!empty($customlinks)) { + $this->openNode('customlinks'); + foreach($customlinks as $customlink) { + $this->openNode('customlink'); + $this->outputNode($customlink->linktype, 'linktype'); + $this->outputNode($customlink->linklabel, 'linklabel'); + $this->outputNode("linkurl]]>", 'linkurl'); + $this->outputNode("linkicon]]>", 'linkicon'); + $this->outputNode($customlink->sequence, 'sequence'); + $this->closeNode('customlink'); + } + $this->closeNode('customlinks'); + } + } + + /** + * Helper function to log messages + * @param String Message to log + * @param Boolean true appends linebreak, false to avoid it + * @access private + */ + static function log($message, $delim=true) { + Vtiger_Utils::Log($message, $delim); + } +} +?> \ No newline at end of file diff --git a/oss/vtiger/trunk/vtlib/Vtiger/PackageImport.php b/oss/vtiger/trunk/vtlib/Vtiger/PackageImport.php new file mode 100644 index 00000000..e2761dfa --- /dev/null +++ b/oss/vtiger/trunk/vtlib/Vtiger/PackageImport.php @@ -0,0 +1,622 @@ +__getManifestFilePath(); + $unzip->unzip('manifest.xml', $manifestfile); + $this->_modulexml = simplexml_load_file($manifestfile); + unlink($manifestfile); + } + + /** + * Get type of package (as specified in manifest) + */ + function type() { + if(!empty($this->_modulexml) && !empty($this->_modulexml->type)) { + return $this->_modulexml->type; + } + return false; + } + + /** + * XPath evaluation on the root module node. + * @param String Path expression + */ + function xpath($path) { + return $this->_modulexml->xpath($path); + } + + /** + * Get the value of matching path (instead of complete xpath result) + * @param String Path expression for which value is required + */ + function xpath_value($path) { + $xpathres = $this->xpath($path); + foreach($xpathres as $pathkey=>$pathvalue) { + if($pathkey == $path) return $pathvalue; + } + return false; + } + + /** + * Are we trying to import language package? + */ + function isLanguageType() { + $packagetype = $this->type(); + + if($packagetype) { + $lcasetype = strtolower($packagetype); + if($lcasetype == 'language') return true; + } + return false; + } + + /** + * Get the license of this package + * NOTE: checkzip should have been called earlier. + */ + function getLicense() { + return $this->_licensetext; + } + + /** + * Check if zipfile is a valid package + * @access private + */ + function checkZip($zipfile) { + $unzip = new Vtiger_Unzip($zipfile); + $filelist = $unzip->getList(); + + $manifestxml_found = false; + $languagefile_found = false; + $vtigerversion_found = false; + + $modulename = null; + $language_modulename = null; + + foreach($filelist as $filename=>$fileinfo) { + $matches = Array(); + preg_match('/manifest.xml/', $filename, $matches); + if(count($matches)) { + $manifestxml_found = true; + $this->__parseManifestFile($unzip); + $modulename = $this->_modulexml->name; + + // Do we need to check the zip further? + if($this->isLanguageType()) { + $languagefile_found = true; // No need to search for module language file. + break; + } else { + continue; + } + } + // Check for language file. + preg_match("/modules\/([^\/]+)\/language\/en_us.lang.php/", $filename, $matches); + if(count($matches)) { $language_modulename = $matches[1]; continue; } + } + + // Verify module language file. + if(!empty($language_modulename) && $language_modulename == $modulename) { + $languagefile_found = true; + } + + if(!empty($this->_modulexml) && + !empty($this->_modulexml->dependencies) && + !empty($this->_modulexml->dependencies->vtiger_version)) { + $vtigerversion_found = true; + } + + $validzip = false; + if($manifestxml_found && $languagefile_found && $vtigerversion_found) + $validzip = true; + + if($validzip) { + if(!empty($this->_modulexml->license)) { + if(!empty($this->_modulexml->license->inline)) { + $this->_licensetext = $this->_modulexml->license->inline; + } else if(!empty($this->_modulexml->license->file)) { + $licensefile = $this->_modulexml->license->file; + $licensefile = "$licensefile"; + if(!empty($filelist[$licensefile])) { + $this->_licensetext = $unzip->unzip($licensefile); + } else { + $this->_licensetext = "Missing $licensefile!"; + } + } + } + } + + if($unzip) $unzip->close(); + + return $validzip; + } + + /** + * Get module name packaged in the zip file + * @access private + */ + function getModuleNameFromZip($zipfile) { + if(!$this->checkZip($zipfile)) return null; + + return $this->_modulexml->name; + } + + /** + * Cache the field instance for re-use + * @access private + */ + function __AddModuleFieldToCache($moduleInstance, $fieldname, $fieldInstance) { + $this->_modulefields_cache["$moduleInstance->name"]["$fieldname"] = $fieldInstance; + } + + /** + * Get field instance from cache + * @access private + */ + function __GetModuleFieldFromCache($moduleInstance, $fieldname) { + return $this->_modulefields_cache["$moduleInstance->name"]["$fieldname"]; + } + + /** + * Initialize Import + * @access private + */ + function initImport($zipfile, $overwrite) { + $module = $this->getModuleNameFromZip($zipfile); + if($module != null) { + $unzip = new Vtiger_Unzip($zipfile, $overwrite); + + // Unzip selectively + $unzip->unzipAllEx( ".", + Array( + // Include only file/folders that need to be extracted + 'include' => Array('templates', "modules/$module", 'cron'), + //'exclude' => Array('manifest.xml') + // NOTE: If excludes is not given then by those not mentioned in include are ignored. + ), + // What files needs to be renamed? + Array( + // Templates folder + 'templates' => "Smarty/templates/modules/$module", + // Cron folder + 'cron' => "cron/modules/$module" + ) + ); + + // If data is not yet available + if(empty($this->_modulexml)) { + $this->__parseManifestFile($unzip); + } + + if($unzip) $unzip->close(); + } + return $module; + } + + /** + * Get dependent version + * @access private + */ + function getDependentVtigerVersion() { + return $this->_modulexml->dependencies->vtiger_version; + } + + /** + * Get package version + * @access private + */ + function getVersion() { + return $this->_modulexml->version; + } + + /** + * Import Module from zip file + * @param String Zip file name + * @param Boolean True for overwriting existing module + * + * @todo overwrite feature is not functionally currently. + */ + function import($zipfile, $overwrite=false) { + $module = $this->initImport($zipfile, $overwrite); + + // Call module import function + $this->import_Module(); + } + + /** + * Import Module + * @access private + */ + function import_Module() { + $tabname = $this->_modulexml->name; + $tablabel= $this->_modulexml->label; + $parenttab=(string)$this->_modulexml->parent; + $tabversion=$this->_modulexml->version; + + $isextension= false; + if(!empty($this->_modulexml->type)) { + $type = strtolower($this->_modulexml->type); + if($type == 'extension' || $type == 'language') + $isextension = true; + } + + $moduleInstance = new Vtiger_Module(); + $moduleInstance->name = $tabname; + $moduleInstance->label= $tablabel; + $moduleInstance->isentitytype = ($isextension != true); + $moduleInstance->version = (!$tabversion)? 0 : $tabversion; + $moduleInstance->save(); + + if(!empty($parenttab)) { + $menuInstance = Vtiger_Menu::getInstance($parenttab); + $menuInstance->addModule($moduleInstance); + } + + $this->import_Tables($this->_modulexml); + $this->import_Blocks($this->_modulexml, $moduleInstance); + $this->import_CustomViews($this->_modulexml, $moduleInstance); + $this->import_SharingAccess($this->_modulexml, $moduleInstance); + $this->import_Events($this->_modulexml, $moduleInstance); + $this->import_Actions($this->_modulexml, $moduleInstance); + $this->import_RelatedLists($this->_modulexml, $moduleInstance); + $this->import_CustomLinks($this->_modulexml, $moduleInstance); + + Vtiger_Module::fireEvent($moduleInstance->name, + Vtiger_Module::EVENT_MODULE_POSTINSTALL); + + $moduleInstance->initWebservice(); + } + + /** + * Import Tables of the module + * @access private + */ + function import_Tables($modulenode) { + if(empty($modulenode->tables) || empty($modulenode->tables->table)) return; + + /** + * Record the changes in schema file + */ + $schemafile = fopen("modules/$modulenode->name/schema.xml", 'w'); + if($schemafile) { + fwrite($schemafile, "\n"); + fwrite($schemafile, "\n"); + fwrite($schemafile, "\t\n"); + } + + // Import the table via queries + foreach($modulenode->tables->table as $tablenode) { + $tablename = $tablenode->name; + $tablesql = "$tablenode->sql"; // Convert to string format + + // Save the information in the schema file. + fwrite($schemafile, "\t\t\n"); + fwrite($schemafile, "\t\t\t$tablename\n"); + fwrite($schemafile, "\t\t\t\n"); + fwrite($schemafile, "\t\t
\n"); + + // Avoid executing SQL that will DELETE or DROP table data + if(Vtiger_Utils::IsCreateSql($tablesql)) { + if(!Vtiger_Utils::checkTable($tablename)) { + self::log("SQL: $tablesql ... ", false); + Vtiger_Utils::ExecuteQuery($tablesql); + self::log("DONE"); + } + } else { + if(Vtiger_Utils::IsDestructiveSql($tablesql)) { + self::log("SQL: $tablesql ... SKIPPED"); + } else { + self::log("SQL: $tablesql ... ", false); + Vtiger_Utils::ExecuteQuery($tablesql); + self::log("DONE"); + } + } + } + if($schemafile) { + fwrite($schemafile, "\t
\n"); + fwrite($schemafile, "
\n"); + fclose($schemafile); + } + } + + /** + * Import Blocks of the module + * @access private + */ + function import_Blocks($modulenode, $moduleInstance) { + if(empty($modulenode->blocks) || empty($modulenode->blocks->block)) return; + foreach($modulenode->blocks->block as $blocknode) { + $blockInstance = $this->import_Block($modulenode, $moduleInstance, $blocknode); + $this->import_Fields($blocknode, $blockInstance, $moduleInstance); + } + } + + /** + * Import Block of the module + * @access private + */ + function import_Block($modulenode, $moduleInstance, $blocknode) { + $blocklabel = $blocknode->label; + + $blockInstance = new Vtiger_Block(); + $blockInstance->label = $blocklabel; + $moduleInstance->addBlock($blockInstance); + return $blockInstance; + } + + /** + * Import Fields of the module + * @access private + */ + function import_Fields($blocknode, $blockInstance, $moduleInstance) { + if(empty($blocknode->fields) || empty($blocknode->fields->field)) return; + + foreach($blocknode->fields->field as $fieldnode) { + $fieldInstance = $this->import_Field($blocknode, $blockInstance, $moduleInstance, $fieldnode); + } + } + + /** + * Import Field of the module + * @access private + */ + function import_Field($blocknode, $blockInstance, $moduleInstance, $fieldnode) { + $fieldInstance = new Vtiger_Field(); + $fieldInstance->name = $fieldnode->fieldname; + $fieldInstance->label = $fieldnode->fieldlabel; + $fieldInstance->table = $fieldnode->tablename; + $fieldInstance->column = $fieldnode->columnname; + $fieldInstance->uitype = $fieldnode->uitype; + $fieldInstance->generatedtype= $fieldnode->generatedtype; + $fieldInstance->readonly = $fieldnode->readonly; + $fieldInstance->presence = $fieldnode->presence; + $fieldInstance->selected = $fieldnode->selected; + $fieldInstance->maximumlength= $fieldnode->maximumlength; + $fieldInstance->sequence = $fieldnode->sequence; + $fieldInstance->quickcreate = $fieldnode->quickcreate; + $fieldInstance->quicksequence= $fieldnode->quickcreatesequence; + $fieldInstance->typeofdata = $fieldnode->typeofdata; + $fieldInstance->displaytype = $fieldnode->displaytype; + $fieldInstance->info_type = $fieldnode->info_type; + + if(!empty($fieldnode->helpinfo)) + $fieldInstance->helpinfo = $fieldnode->helpinfo; + + if(isset($fieldnode->masseditable)) + $fieldInstance->masseditable = $fieldnode->masseditable; + + if(isset($fieldnode->columntype) && !empty($fieldnode->columntype)) + $fieldInstance->columntype = $fieldnode->columntype; + + $blockInstance->addField($fieldInstance); + + // Set the field as entity identifier if marked. + if(!empty($fieldnode->entityidentifier)) { + $moduleInstance->entityidfield = $fieldnode->entityidentifier->entityidfield; + $moduleInstance->entityidcolumn= $fieldnode->entityidentifier->entityidcolumn; + $moduleInstance->setEntityIdentifier($fieldInstance); + } + + // Check picklist values associated with field if any. + if(!empty($fieldnode->picklistvalues) && !empty($fieldnode->picklistvalues->picklistvalue)) { + $picklistvalues = Array(); + foreach($fieldnode->picklistvalues->picklistvalue as $picklistvaluenode) { + $picklistvalues[] = $picklistvaluenode; + } + $fieldInstance->setPicklistValues( $picklistvalues ); + } + + // Check related modules associated with this field + if(!empty($fieldnode->relatedmodules) && !empty($fieldnode->relatedmodules->relatedmodule)) { + $relatedmodules = Array(); + foreach($fieldnode->relatedmodules->relatedmodule as $relatedmodulenode) { + $relatedmodules[] = $relatedmodulenode; + } + $fieldInstance->setRelatedModules($relatedmodules); + } + + $this->__AddModuleFieldToCache($moduleInstance, $fieldnode->fieldname, $fieldInstance); + return $fieldInstance; + } + + /** + * Import Custom views of the module + * @access private + */ + function import_CustomViews($modulenode, $moduleInstance) { + if(empty($modulenode->customviews) || empty($modulenode->customviews->customview)) return; + foreach($modulenode->customviews->customview as $customviewnode) { + $filterInstance = $this->import_CustomView($modulenode, $moduleInstance, $customviewnode); + + } + } + + /** + * Import Custom View of the module + * @access private + */ + function import_CustomView($modulenode, $moduleInstance, $customviewnode) { + $viewname = $customviewnode->viewname; + $setdefault=$customviewnode->setdefault; + $setmetrics=$customviewnode->setmetrics; + + $filterInstance = new Vtiger_Filter(); + $filterInstance->name = $viewname; + $filterInstance->isdefault = $setdefault; + $filterInstance->inmetrics = $setmetrics; + + $moduleInstance->addFilter($filterInstance); + + foreach($customviewnode->fields->field as $fieldnode) { + $fieldInstance = $this->__GetModuleFieldFromCache($moduleInstance, $fieldnode->fieldname); + $filterInstance->addField($fieldInstance, $fieldnode->columnindex); + + if(!empty($fieldnode->rules->rule)) { + foreach($fieldnode->rules->rule as $rulenode) { + $filterInstance->addRule($fieldInstance, $rulenode->comparator, $rulenode->value, $rulenode->columnindex); + } + } + } + } + + /** + * Import Sharing Access of the module + * @access private + */ + function import_SharingAccess($modulenode, $moduleInstance) { + if(empty($modulenode->sharingaccess)) return; + + if(!empty($modulenode->sharingaccess->default)) { + foreach($modulenode->sharingaccess->default as $defaultnode) { + $moduleInstance->setDefaultSharing($defaultnode); + } + } + } + + /** + * Import Events of the module + * @access private + */ + function import_Events($modulenode, $moduleInstance) { + if(empty($modulenode->events) || empty($modulenode->events->event)) return; + + if(Vtiger_Event::hasSupport()) { + foreach($modulenode->events->event as $eventnode) { + $this->import_Event($modulenode, $moduleInstance, $eventnode); + } + } + } + + /** + * Import Event of the module + * @access private + */ + function import_Event($modulenode, $moduleInstance, $eventnode) { + $event_condition = ''; + if(!empty($eventnode->condition)) $event_condition = "$eventnode->condition"; + Vtiger_Event::register($moduleInstance, + (string)$eventnode->eventname, (string)$eventnode->classname, + (string)$eventnode->filename, (string)$event_condition + ); + } + + /** + * Import actions of the module + * @access private + */ + function import_Actions($modulenode, $moduleInstance) { + if(empty($modulenode->actions) || empty($modulenode->actions->action)) return; + foreach($modulenode->actions->action as $actionnode) { + $this->import_Action($modulenode, $moduleInstance, $actionnode); + } + } + + /** + * Import action of the module + * @access private + */ + function import_Action($modulenode, $moduleInstance, $actionnode) { + $actionstatus = $actionnode->status; + if($actionstatus == 'enabled') + $moduleInstance->enableTools($actionnode->name); + else + $moduleInstance->disableTools($actionnode->name); + } + + /** + * Import related lists of the module + * @access private + */ + function import_RelatedLists($modulenode, $moduleInstance) { + if(empty($modulenode->relatedlists) || empty($modulenode->relatedlists->relatedlist)) return; + foreach($modulenode->relatedlists->relatedlist as $relatedlistnode) { + $relModuleInstance = $this->import_Relatedlist($modulenode, $moduleInstance, $relatedlistnode); + } + } + + /** + * Import related list of the module. + * @access private + */ + function import_Relatedlist($modulenode, $moduleInstance, $relatedlistnode) { + $relModuleInstance = Vtiger_Module::getInstance($relatedlistnode->relatedmodule); + $label = $relatedlistnode->label; + $actions = false; + if(!empty($relatedlistnode->actions) && !empty($relatedlistnode->actions->action)) { + $actions = Array(); + foreach($relatedlistnode->actions->action as $actionnode) { + $actions[] = "$actionnode"; + } + } + if($relModuleInstance) { + $moduleInstance->setRelatedList($relModuleInstance, "$label", $actions, "$relatedlistnode->function"); + } + return $relModuleInstance; + } + + /** + * Import custom links of the module. + * @access private + */ + function import_CustomLinks($modulenode, $moduleInstance) { + if(empty($modulenode->customlinks) || empty($modulenode->customlinks->customlink)) return; + + foreach($modulenode->customlinks->customlink as $customlinknode) { + $moduleInstance->addLink( + "$customlinknode->linktype", + "$customlinknode->linklabel", + "$customlinknode->linkurl", + "$customlinknode->linkicon", + "$customlinknode->sequence" + ); + } + } +} +?> diff --git a/oss/vtiger/trunk/vtlib/Vtiger/PackageUpdate.php b/oss/vtiger/trunk/vtlib/Vtiger/PackageUpdate.php new file mode 100644 index 00000000..6f52b809 --- /dev/null +++ b/oss/vtiger/trunk/vtlib/Vtiger/PackageUpdate.php @@ -0,0 +1,336 @@ +getModuleNameFromZip($zipfile); + + if(!$moduleInstance || $moduleInstance->name != $module) { + self::log('Module name mismatch!'); + return false; + } + + if($module != null) { + $unzip = new Vtiger_Unzip($zipfile, $overwrite); + + // Unzip selectively + $unzip->unzipAllEx( ".", + Array( + 'include' => Array('templates', "modules/$module"), // We don't need manifest.xml + //'exclude' => Array('manifest.xml') // DEFAULT: excludes all not in include + ), + // Templates folder to be renamed while copying + Array('templates' => "Smarty/templates/modules/$module"), + + // Cron folder to be renamed while copying + Array('cron' => "cron/modules/$module") + ); + + // If data is not yet available + if(empty($this->_modulexml)) { + $this->__parseManifestFile($unzip); + } + + if($unzip) $unzip->close(); + } + return $module; + } + + /** + * Update Module from zip file + * @param Vtiger_Module Instance of the module to update + * @param String Zip file name + * @param Boolean True for overwriting existing module + */ + function update($moduleInstance, $zipfile, $overwrite=true) { + $module = $this->initUpdate($moduleInstance, $zipfile, $overwrite); + + if($module) { + // Call module update function + $this->update_Module($moduleInstance); + } + } + + /** + * Update Module + * @access private + */ + function update_Module($moduleInstance) { + $tabname = $this->_modulexml->name; + $tablabel= $this->_modulexml->label; + $parenttab=$this->_modulexml->parent; + $tabversion=$this->_modulexml->version; + + $isextension= false; + if(!empty($this->_modulexml->type)) { + $type = strtolower($this->_modulexml->type); + if($type == 'extension' || $type == 'language') + $isextension = true; + } + + Vtiger_Module::fireEvent($moduleInstance->name, + Vtiger_Module::EVENT_MODULE_PREUPDATE); + + // TODO Handle module property changes like menu, label etc... + /*if(!empty($parenttab) && $parenttab != '') { + $menuInstance = Vtiger_Menu::getInstance($parenttab); + $menuInstance->addModule($moduleInstance); + }*/ + + $this->handle_Migration($this->_modulexml, $moduleInstance); + + $this->update_Tables($this->_modulexml); + $this->update_Blocks($this->_modulexml, $moduleInstance); + $this->update_CustomViews($this->_modulexml, $moduleInstance); + $this->update_SharingAccess($this->_modulexml, $moduleInstance); + $this->update_Events($this->_modulexml, $moduleInstance); + $this->update_Actions($this->_modulexml, $moduleInstance); + $this->update_RelatedLists($this->_modulexml, $moduleInstance); + + $moduleInstance->__updateVersion($tabversion); + + Vtiger_Module::fireEvent($moduleInstance->name, + Vtiger_Module::EVENT_MODULE_POSTUPDATE); + } + + /** + * Parse migration information from manifest + * @access private + */ + function parse_Migration($modulenode) { + if(!$this->_migrations) { + $this->_migrations = Array(); + if(!empty($modulenode->migrations) && + !empty($modulenode->migrations->migration)) { + foreach($modulenode->migrations->migration as $migrationnode) { + $migrationattrs = $migrationnode->attributes(); + $migrationversion = $migrationattrs['version']; + $this->_migrations["$migrationversion"] = $migrationnode; + } + } + // Sort the migration details based on version + if(count($this->_migrations) > 1) { + uksort($this->_migrations, 'version_compare'); + } + } + } + + /** + * Handle migration of the module + * @access private + */ + function handle_Migration($modulenode, $moduleInstance) { + // TODO Handle module migration SQL + $this->parse_Migration($modulenode); + $cur_version = $moduleInstance->version; + foreach($this->_migrations as $migversion=>$migrationnode) { + // Perform migration only for higher version than current + if(version_compare($cur_version, $migversion, '<')) { + self::log("Migrating to $migversion ... STARTED"); + if(!empty($migrationnode->tables) && !empty($migrationnode->tables->table)) { + foreach($migrationnode->tables->table as $tablenode) { + $tablename = $tablenode->name; + $tablesql = "$tablenode->sql"; // Convert to string + + // Skip SQL which are destructive + if(Vtiger_Utils::IsDestructiveSql($tablesql)) { + self::log("SQL: $tablesql ... SKIPPED"); + } else { + // Supress any SQL query failures + self::log("SQL: $tablesql ... ", false); + Vtiger_Utils::ExecuteQuery($tablesql, true); + self::log("DONE"); + } + } + } + self::log("Migrating to $migversion ... DONE"); + } + } + } + + /** + * Update Tables of the module + * @access private + */ + function update_Tables($modulenode) { + $this->import_Tables($modulenode); + } + + /** + * Update Blocks of the module + * @access private + */ + function update_Blocks($modulenode, $moduleInstance) { + if(empty($modulenode->blocks) || empty($modulenode->blocks->block)) return; + + foreach($modulenode->blocks->block as $blocknode) { + $blockInstance = Vtiger_Block::getInstance($blocknode->label, $moduleInstance); + if(!$blockInstance) { + $blockInstance = $this->import_Block($modulenode, $moduleInstance, $blocknode); + } else { + $this->update_Block($modulenode, $moduleInstance, $blocknode, $blockInstance); + } + + $this->update_Fields($blocknode, $blockInstance, $moduleInstance); + } + } + + /** + * Update Block of the module + * @access private + */ + function update_Block($modulenode, $moduleInstance, $blocknode, $blockInstance) { + // TODO Handle block property update + } + + /** + * Update Fields of the module + * @access private + */ + function update_Fields($blocknode, $blockInstance, $moduleInstance) { + if(empty($blocknode->fields) || empty($blocknode->fields->field)) return; + + foreach($blocknode->fields->field as $fieldnode) { + $fieldInstance = Vtiger_Field::getInstance($fieldnode->fieldname, $moduleInstance); + if(!$fieldInstance) { + $fieldInstance = $this->import_Field($blocknode, $blockInstance, $moduleInstance, $fieldnode); + } else { + $this->update_Field($blocknode, $blockInstance, $moduleInstance, $fieldnode, $fieldInstance); + } + $this->__AddModuleFieldToCache($moduleInstance, $fieldInstance->name, $fieldInstance); + } + } + + /** + * Update Field of the module + * @access private + */ + function update_Field($blocknode, $blockInstance, $moduleInstance, $fieldnode, $fieldInstance) { + // TODO Handle field property update + + if(!empty($fieldnode->helpinfo)) $fieldInstance->setHelpInfo($fieldnode->helpinfo); + if(!empty($fieldnode->masseditable)) $fieldInstance->setMassEditable($fieldnode->masseditable); + } + + /** + * Import Custom views of the module + * @access private + */ + function update_CustomViews($modulenode, $moduleInstance) { + if(empty($modulenode->customviews) || empty($modulenode->customviews->customview)) return; + foreach($modulenode->customviews->customview as $customviewnode) { + $filterInstance = Vtiger_Filter::getInstance($customviewnode->viewname, $moduleInstance); + if(!$filterInstance) { + $filterInstance = $this->import_CustomView($modulenode, $moduleInstance, $customviewnode); + } else { + $this->update_CustomView($modulenode, $moduleInstance, $customviewnode, $filterInstance); + } + } + } + + /** + * Update Custom View of the module + * @access private + */ + function update_CustomView($modulenode, $moduleInstance, $customviewnode, $filterInstance) { + // TODO Handle filter property update + } + + /** + * Update Sharing Access of the module + * @access private + */ + function update_SharingAccess($modulenode, $moduleInstance) { + if(empty($modulenode->sharingaccess)) return; + + // TODO Handle sharing access property update + } + + /** + * Update Events of the module + * @access private + */ + function update_Events($modulenode, $moduleInstance) { + if(empty($modulenode->events) || empty($modulenode->events->event)) return; + + if(Vtiger_Event::hasSupport()) { + foreach($modulenode->events->event as $eventnode) { + $this->update_Event($modulenode, $moduleInstance, $eventnode); + } + } + } + + /** + * Update Event of the module + * @access private + */ + function update_Event($modulenode, $moduleInstance, $eventnode) { + //Vtiger_Event::register($moduleInstance, $eventnode->eventname, $eventnode->classname, $eventnode->filename); + // TODO Handle event property update + } + + /** + * Update actions of the module + * @access private + */ + function update_Actions($modulenode, $moduleInstance) { + if(empty($modulenode->actions) || empty($modulenode->actions->action)) return; + foreach($modulenode->actions->action as $actionnode) { + $this->update_Action($modulenode, $moduleInstance, $actionnode); + } + } + + /** + * Update action of the module + * @access private + */ + function update_Action($modulenode, $moduleInstance, $actionnode) { + // TODO Handle action property update + } + + /** + * Update related lists of the module + * @access private + */ + function update_RelatedLists($modulenode, $moduleInstance) { + if(empty($modulenode->relatedlists) || empty($modulenode->relatedlists->relatedlist)) return; + foreach($modulenode->relatedlists->relatedlist as $relatedlistnode) { + $relModuleInstance = $this->import_Relatedlist($modulenode, $moduleInstance, $relatedlistnode); + } + } + + /** + * Import related list of the module. + * @access private + */ + function update_Relatedlist($modulenode, $moduleInstance, $relatedlistnode) { + // TODO Handle related list update + } +} +?> diff --git a/oss/vtiger/trunk/vtlib/Vtiger/Profile.php b/oss/vtiger/trunk/vtlib/Vtiger/Profile.php new file mode 100644 index 00000000..b181145a --- /dev/null +++ b/oss/vtiger/trunk/vtlib/Vtiger/Profile.php @@ -0,0 +1,120 @@ +pquery("INSERT INTO vtiger_def_org_field (tabid, fieldid, visible, readonly) VALUES(?,?,?,?)", + Array($fieldInstance->getModuleId(), $fieldInstance->id, '0', '1')); + + $profileids = self::getAllIds(); + foreach($profileids as $profileid) { + $adb->pquery("INSERT INTO vtiger_profile2field (profileid, tabid, fieldid, visible, readonly) VALUES(?,?,?,?,?)", + Array($profileid, $fieldInstance->getModuleId(), $fieldInstance->id, '0', '1')); + } + } + + /** + * Delete profile information related with field. + * @param Vtiger_Field Instance of the field + * @access private + */ + static function deleteForField($fieldInstance) { + global $adb; + + $adb->pquery("DELETE FROM vtiger_def_org_field WHERE fieldid=?", Array($fieldInstance->id)); + $adb->pquery("DELETE FROM vtiger_profile2field WHERE fieldid=?", Array($fieldInstance->id)); + } + + /** + * Get all the existing profile ids + * @access private + */ + static function getAllIds() { + global $adb; + $profileids = Array(); + $result = $adb->query('SELECT profileid FROM vtiger_profile'); + for($index = 0; $index < $adb->num_rows($result); ++$index) { + $profileids[] = $adb->query_result($result, $index, 'profileid'); + } + return $profileids; + } + + /** + * Initialize profile setup for the module + * @param Vtiger_Module Instance of module + * @access private + */ + static function initForModule($moduleInstance) { + global $adb; + + $actionids = Array(); + $result = $adb->query("SELECT actionid from vtiger_actionmapping WHERE actionname IN + ('Save','EditView','Delete','index','DetailView')"); + /* + * NOTE: Other actionname (actionid >= 5) is considered as utility (tools) for a profile. + * Gather all the actionid for associating to profile. + */ + for($index = 0; $index < $adb->num_rows($result); ++$index) { + $actionids[] = $adb->query_result($result, $index, 'actionid'); + } + + $profileids = self::getAllIds(); + + foreach($profileids as $profileid) { + $adb->pquery("INSERT INTO vtiger_profile2tab (profileid, tabid, permissions) VALUES (?,?,?)", + Array($profileid, $moduleInstance->id, 0)); + + if($moduleInstance->isentitytype) { + foreach($actionids as $actionid) { + $adb->pquery( + "INSERT INTO vtiger_profile2standardpermissions (profileid, tabid, Operation, permissions) VALUES(?,?,?,?)", + Array($profileid, $moduleInstance->id, $actionid, 0)); + } + } + } + self::log("Initializing module permissions ... DONE"); + } + + /** + * Delete profile setup of the module + * @param Vtiger_Module Instance of module + * @access private + */ + static function deleteForModule($moduleInstance) { + global $adb; + $adb->pquery("DELETE FROM vtiger_profile2tab WHERE tabid=?", Array($moduleInstance->id)); + $adb->pquery("DELETE FROM vtiger_profile2standardpermissions WHERE tabid=?", Array($moduleInstance->id)); + } +} +?> diff --git a/oss/vtiger/trunk/vtlib/Vtiger/Unzip.php b/oss/vtiger/trunk/vtlib/Vtiger/Unzip.php new file mode 100644 index 00000000..42713dc4 --- /dev/null +++ b/oss/vtiger/trunk/vtlib/Vtiger/Unzip.php @@ -0,0 +1,122 @@ + Array('zipfilepath1', 'zipfilepath2', ...), + * 'exclude'=> Array('zipfilepath3', ...) + * ) + * + * DEFAULT: If include is specified only files under the specified path will be included. + * If exclude is specified folders or files will be excluded. + */ + if($includeExclude === false) $includeExclude = Array(); + + $lista = $this->getList(); + if(sizeof($lista)) foreach($lista as $fileName=>$trash){ + // Should the file be ignored? + if($includeExclude['include'] && + !$this->__checkPathInArray($fileName, $includeExclude['include'])) { + // Do not include something not specified in include + continue; + } + if($includeExclude['exclude'] && + $this->__checkPathInArray($fileName, $includeExclude['exclude'])) { + // Do not include something not specified in include + continue; + } + // END + + $dirname = dirname($fileName); + + // Rename the path with the matching one (as specified) + if(!empty($renamePaths)) { + foreach($renamePaths as $lookup => $replace) { + if(strpos($dirname, $lookup) === 0) { + $dirname = substr_replace($dirname, $replace, 0, strlen($lookup)); + break; + } + } + } + // END + + $outDN = "$targetDir/$dirname"; + + if(substr($dirname, 0, strlen($baseDir)) != $baseDir) + continue; + + if(!is_dir($outDN) && $maintainStructure){ + $str = ""; + $folders = explode("/", $dirname); + foreach($folders as $folder){ + $str = $str?"$str/$folder":$folder; + if(!is_dir("$targetDir/$str")){ + $this->debugMsg(1, "Creating folder: $targetDir/$str"); + mkdir("$targetDir/$str"); + if($applyChmod) + chmod("$targetDir/$str", $applyChmod); + } + } + } + if(substr($fileName, -1, 1) == "/") + continue; + + $this->unzip($fileName, "$targetDir/$dirname/".basename($fileName), $applyChmod); + } + } + +} +?> diff --git a/oss/vtiger/trunk/vtlib/Vtiger/Utils.php b/oss/vtiger/trunk/vtlib/Vtiger/Utils.php new file mode 100644 index 00000000..9a972f5a --- /dev/null +++ b/oss/vtiger/trunk/vtlib/Vtiger/Utils.php @@ -0,0 +1,227 @@ +debug($message); + if(!isset($Vtiger_Utils_Log) || $Vtiger_Utils_Log == false) return; + + print_r($message); + if($delimit) { + if(isset($_REQUEST)) echo "
"; + else echo "\n"; + } + } + + /** + * Escape the string to avoid SQL Injection attacks. + * @param String Sql statement string + */ + static function SQLEscape($value) { + if($value == null) return $value; + global $adb; + return $adb->sql_escape_string($value); + } + + /** + * Check if table is present in database + * @param String tablename to check + */ + static function CheckTable($tablename) { + global $adb; + $old_dieOnError = $adb->dieOnError; + $adb->dieOnError = false; + + $tablename = Vtiger_Utils::SQLEscape($tablename); + $tablecheck = $adb->query("SELECT 1 FROM $tablename LIMIT 1"); + + $tablePresent = true; + if(empty($tablecheck)) + $tablePresent = false; + + $adb->dieOnError = $old_dieOnError; + return $tablePresent; + } + + /** + * Create table (supressing failure) + * @param String tablename to create + * @param String table creation criteria like '(columnname columntype, ....)' + * @param String Optional suffix to add during table creation + *
+ * will be appended to CREATE TABLE $tablename SQL + */ + static function CreateTable($tablename, $criteria, $suffixTableMeta=false) { + global $adb; + + $org_dieOnError = $adb->dieOnError; + $adb->dieOnError = false; + $sql = "CREATE TABLE " . $tablename . $criteria; + if($suffixTableMeta !== false) { + if($suffixTableMeta === true) { + if($adb->isMySQL()) { + $suffixTableMeta = ' ENGINE=InnoDB DEFAULT CHARSET=utf8'; + } else { + // TODO Handle other database types. + } + } + $sql .= $suffixTableMeta; + } + $adb->query($sql); + $adb->dieOnError = $org_dieOnError; + } + + /** + * Alter existing table + * @param String tablename to alter + * @param String alter criteria like ' ADD columnname columntype'
+ * will be appended to ALTER TABLE $tablename SQL + */ + static function AlterTable($tablename, $criteria) { + global $adb; + $adb->query("ALTER TABLE " . $tablename . $criteria); + } + + /** + * Add column to existing table + * @param String tablename to alter + * @param String columnname to add + * @param String columntype (criteria like 'VARCHAR(100)') + */ + static function AddColumn($tablename, $columnname, $criteria) { + global $adb; + if(!in_array($columnname, $adb->getColumnNames($tablename))) { + self::AlterTable($tablename, " ADD COLUMN $columnname $criteria"); + } + } + + /** + * Get SQL query + * @param String SQL query statement + */ + static function ExecuteQuery($sqlquery, $supressdie=false) { + global $adb; + $old_dieOnError = $adb->dieOnError; + + if($supressdie) $adb->dieOnError = false; + + $adb->query($sqlquery); + + $adb->dieOnError = $old_dieOnError; + } + + /** + * Get CREATE SQL for given table + * @param String tablename for which CREATE SQL is requried + */ + static function CreateTableSql($tablename) { + global $adb; + + $create_table = $adb->query("SHOW CREATE TABLE $tablename"); + $sql = decode_html($adb->query_result($create_table, 0, 1)); + return $sql; + } + + /** + * Check if the given SQL is a CREATE statement + * @param String SQL String + */ + static function IsCreateSql($sql) { + if(preg_match('/(CREATE TABLE)/', strtoupper($sql))) { + return true; + } + return false; + } + + /** + * Check if the given SQL is destructive (DELETE's DATA) + * @param String SQL String + */ + static function IsDestructiveSql($sql) { + if(preg_match('/(DROP TABLE)|(DROP COLUMN)|(DELETE FROM)/', + strtoupper($sql))) { + return true; + } + return false; + } +} +?> \ No newline at end of file diff --git a/oss/vtiger/trunk/vtlib/Vtiger/Utils/StringTemplate.php b/oss/vtiger/trunk/vtlib/Vtiger/Utils/StringTemplate.php new file mode 100644 index 00000000..e2d53979 --- /dev/null +++ b/oss/vtiger/trunk/vtlib/Vtiger/Utils/StringTemplate.php @@ -0,0 +1,115 @@ +tplvars[$key] = $value; + } + + /** + * Get replacement value for the variable. + */ + function get($key) { + $value = false; + if(isset($this->tplvars[$key])) { + $value = $this->tplvars[$key]; + } + return $value; + } + + /** + * Clear all the assigned variable values. + * (except the once in the given list) + */ + function clear($exceptvars=false) { + $restorevars = Array(); + if($exceptvars) { + foreach($exceptvars as $varkey) { + $restorevars[$varkey] = $this->get($varkey); + } + } + unset($this->tplvars); + + $this->tplvars = Array(); + foreach($restorevars as $key=>$val) $this->assign($key, $val); + } + + /** + * Merge the given file with variable values assigned. + * @param $instring input string template + * @param $avoidLookup should be true if only verbatim file copy needs to be done + * @returns merged contents + */ + function merge($instring, $avoidLookup=false) { + if(empty($instring)) return $instring; + + if(!$avoidLookup) { + + /** Look for variables */ + $matches = Array(); + preg_match_all($this->_lookfor, $instring, $matches); + + /** Replace variables found with value assigned. */ + $matchcount = count($matches[1]); + for($index = 0; $index < $matchcount; ++$index) { + $matchstr = $matches[0][$index]; + $matchkey = $matches[1][$index]; + + $matchstr_regex = $this->__formatAsRegex($matchstr); + + $replacewith = $this->get($matchkey); + if($replacewith) { + $instring = preg_replace( + "/$matchstr_regex/", $replacewith, $instring); + } + } + } + return $instring; + } + + /** + * Clean up the input to be used as a regex + * @access private + */ + function __formatAsRegex($value) { + // If / is not already escaped as \/ do it now + $value = preg_replace('/\//', '\\/', $value); + // If $ is not already escaped as \$ do it now + $value = preg_replace('/(? diff --git a/oss/vtiger/trunk/vtlib/Vtiger/Version.php b/oss/vtiger/trunk/vtlib/Vtiger/Version.php new file mode 100644 index 00000000..efc43b2f --- /dev/null +++ b/oss/vtiger/trunk/vtlib/Vtiger/Version.php @@ -0,0 +1,36 @@ +', '>=') + */ + static function check($with_version, $condition='=') { + $current_version = self::current(); + return version_compare($current_version, $with_version, $condition); + } +} +?> diff --git a/oss/vtiger/trunk/vtlib/Vtiger/Webservice.php b/oss/vtiger/trunk/vtlib/Vtiger/Webservice.php new file mode 100644 index 00000000..e08f2c22 --- /dev/null +++ b/oss/vtiger/trunk/vtlib/Vtiger/Webservice.php @@ -0,0 +1,42 @@ +isentitytype) { + // TODO: Enable support when webservice API support is added. + if(function_exists('vtws_addDefaultModuleTypeEntity')) { + vtws_addDefaultModuleTypeEntity($moduleInstance->name); + self::log("Initializing webservices support ...DONE"); + } + } + } +} +?> diff --git a/oss/vtiger/trunk/vtlib/Vtiger/Zip.php b/oss/vtiger/trunk/vtlib/Vtiger/Zip.php new file mode 100644 index 00000000..271af65a --- /dev/null +++ b/oss/vtiger/trunk/vtlib/Vtiger/Zip.php @@ -0,0 +1,111 @@ +__normalizePath(realpath($basepath)); + $src_realpath = $this->__normalizePath(realpath($srcpath)); + $search_index = strpos($src_realpath, $base_realpath); + if($search_index === 0) { + $startindex = strlen($base_realpath)+1; + // On windows $base_realpath ends with / and On Linux it will not have / at end! + if(strrpos($base_realpath, '/') == strlen($base_realpath)-1) $startindex -= 1; + $relpath = substr($src_realpath, $startindex); + } + return $relpath; + } + + /** + * Check and add '/' directory separator + */ + function __fixDirSeparator($path) { + if($path != '' && (strripos($path, '/') != strlen($path)-1)) $path .= '/'; + return $path; + } + + /** + * Normalize the directory path separators. + */ + function __normalizePath($path) { + if($path && strpos($path, '\\')!== false) $path = preg_replace("/\\\\/", "/", $path); + return $path; + } + + /** + * Copy the directory on the disk into zip file. + */ + function copyDirectoryFromDisk($dirname, $zipdirname=null, $excludeList=null, $basedirname=null) { + $dir = opendir($dirname); + if(strripos($dirname, '/') != strlen($dirname)-1) + $dirname .= '/'; + + if($basedirname == null) $basedirname = realpath($dirname); + + while(false !== ($file = readdir($dir))) { + if($file != '.' && $file != '..' && + $file != '.svn' && $file != 'CVS') { + // Exclude the file/directory + if(!empty($excludeList) && in_array("$dirname$file", $excludeList)) + continue; + + if(is_dir("$dirname$file")) { + $this->copyDirectoryFromDisk("$dirname$file", $zipdirname, $excludeList, $basedirname); + } else { + $zippath = $dirname; + if($zipdirname != null && $zipdirname != '') { + $zipdirname = $this->__fixDirSeparator($zipdirname); + $zippath = $zipdirname.$this->__getRelativePath($basedirname, $dirname); + } + $this->copyFileFromDisk($dirname, $zippath, $file); + } + } + } + closedir($dir); + } + + /** + * Copy the disk file into the zip. + */ + function copyFileFromDisk($path, $zippath, $file) { + $path = $this->__fixDirSeparator($path); + $zippath = $this->__fixDirSeparator($zippath); + $this->addFile("$path$file", "$zippath$file"); + } +} +?> diff --git a/oss/vtiger/trunk/vtlib/thirdparty/dUnzip2.inc.php b/oss/vtiger/trunk/vtlib/thirdparty/dUnzip2.inc.php new file mode 100644 index 00000000..7aa5dd42 --- /dev/null +++ b/oss/vtiger/trunk/vtlib/thirdparty/dUnzip2.inc.php @@ -0,0 +1,517 @@ + +file_put_contents: Cannot create file $file
"; + return false; + } +} + +class dUnzip2{ + Function getVersion(){ + return "2.6"; + } + // Public + var $fileName; + var $compressedList; // You will problably use only this one! + var $centralDirList; // Central dir list... It's a kind of 'extra attributes' for a set of files + var $endOfCentral; // End of central dir, contains ZIP Comments + var $debug; + + // Private + var $fh; + var $zipSignature = "\x50\x4b\x03\x04"; // local file header signature + var $dirSignature = "\x50\x4b\x01\x02"; // central dir header signature + var $dirSignatureE= "\x50\x4b\x05\x06"; // end of central dir signature + + // Public + Function dUnzip2($fileName){ + $this->fileName = $fileName; + $this->compressedList = + $this->centralDirList = + $this->endOfCentral = Array(); + } + + Function getList($stopOnFile=false){ + if(sizeof($this->compressedList)){ + $this->debugMsg(1, "Returning already loaded file list."); + return $this->compressedList; + } + + // Open file, and set file handler + $fh = fopen($this->fileName, "r"); + $this->fh = &$fh; + if(!$fh){ + $this->debugMsg(2, "Failed to load file."); + return false; + } + + $this->debugMsg(1, "Loading list from 'End of Central Dir' index list..."); + if(!$this->_loadFileListByEOF($fh, $stopOnFile)){ + $this->debugMsg(1, "Failed! Trying to load list looking for signatures..."); + if(!$this->_loadFileListBySignatures($fh, $stopOnFile)){ + $this->debugMsg(1, "Failed! Could not find any valid header."); + $this->debugMsg(2, "ZIP File is corrupted or empty"); + return false; + } + } + + if($this->debug){ + #------- Debug compressedList + $kkk = 0; + echo ""; + foreach($this->compressedList as $fileName=>$item){ + if(!$kkk && $kkk=1){ + echo ""; + foreach($item as $fieldName=>$value) + echo ""; + echo ''; + } + echo ""; + foreach($item as $fieldName=>$value){ + if($fieldName == 'lastmod_datetime') + echo ""; + else + echo ""; + } + echo ""; + } + echo "
$fieldName
".date("d/m/Y H:i:s", $value)."$value
"; + + #------- Debug centralDirList + $kkk = 0; + if(sizeof($this->centralDirList)){ + echo ""; + foreach($this->centralDirList as $fileName=>$item){ + if(!$kkk && $kkk=1){ + echo ""; + foreach($item as $fieldName=>$value) + echo ""; + echo ''; + } + echo ""; + foreach($item as $fieldName=>$value){ + if($fieldName == 'lastmod_datetime') + echo ""; + else + echo ""; + } + echo ""; + } + echo "
$fieldName
".date("d/m/Y H:i:s", $value)."$value
"; + } + + #------- Debug endOfCentral + $kkk = 0; + if(sizeof($this->endOfCentral)){ + echo ""; + echo ""; + foreach($this->endOfCentral as $field=>$value){ + echo ""; + echo ""; + echo ""; + echo ""; + } + echo "
dUnzip - End of file
$field$value
"; + } + } + + return $this->compressedList; + } + Function getExtraInfo($compressedFileName){ + return + isset($this->centralDirList[$compressedFileName])? + $this->centralDirList[$compressedFileName]: + false; + } + Function getZipInfo($detail=false){ + return $detail? + $this->endOfCentral[$detail]: + $this->endOfCentral; + } + + Function unzip($compressedFileName, $targetFileName=false, $applyChmod=0777){ + if(!sizeof($this->compressedList)){ + $this->debugMsg(1, "Trying to unzip before loading file list... Loading it!"); + $this->getList(false, $compressedFileName); + } + + $fdetails = &$this->compressedList[$compressedFileName]; + if(!isset($this->compressedList[$compressedFileName])){ + $this->debugMsg(2, "File '$compressedFileName' is not compressed in the zip."); + return false; + } + if(substr($compressedFileName, -1) == "/"){ + $this->debugMsg(2, "Trying to unzip a folder name '$compressedFileName'."); + return false; + } + if(!$fdetails['uncompressed_size']){ + $this->debugMsg(1, "File '$compressedFileName' is empty."); + return $targetFileName? + file_put_contents($targetFileName, ""): + ""; + } + + fseek($this->fh, $fdetails['contents-startOffset']); + $ret = $this->uncompress( + fread($this->fh, $fdetails['compressed_size']), + $fdetails['compression_method'], + $fdetails['uncompressed_size'], + $targetFileName + ); + if($applyChmod && $targetFileName) + chmod($targetFileName, 0777); + + return $ret; + } + Function unzipAll($targetDir=false, $baseDir="", $maintainStructure=true, $applyChmod=0777){ + if($targetDir === false) + $targetDir = dirname(__FILE__)."/"; + + $lista = $this->getList(); + if(sizeof($lista)) foreach($lista as $fileName=>$trash){ + $dirname = dirname($fileName); + $outDN = "$targetDir/$dirname"; + + if(substr($dirname, 0, strlen($baseDir)) != $baseDir) + continue; + + if(!is_dir($outDN) && $maintainStructure){ + $str = ""; + $folders = explode("/", $dirname); + foreach($folders as $folder){ + $str = $str?"$str/$folder":$folder; + if(!is_dir("$targetDir/$str")){ + $this->debugMsg(1, "Creating folder: $targetDir/$str"); + mkdir("$targetDir/$str"); + if($applyChmod) + chmod("$targetDir/$str", $applyChmod); + } + } + } + if(substr($fileName, -1, 1) == "/") + continue; + + $maintainStructure? + $this->unzip($fileName, "$targetDir/$fileName", $applyChmod): + $this->unzip($fileName, "$targetDir/".basename($fileName), $applyChmod); + } + } + + Function close(){ // Free the file resource + if($this->fh) + fclose($this->fh); + } + Function __destroy(){ + $this->close(); + } + + // Private (you should NOT call these methods): + Function uncompress($content, $mode, $uncompressedSize, $targetFileName=false){ + switch($mode){ + case 0: + // Not compressed + return $targetFileName? + file_put_contents($targetFileName, $content): + $content; + case 1: + $this->debugMsg(2, "Shrunk mode is not supported... yet?"); + return false; + case 2: + case 3: + case 4: + case 5: + $this->debugMsg(2, "Compression factor ".($mode-1)." is not supported... yet?"); + return false; + case 6: + $this->debugMsg(2, "Implode is not supported... yet?"); + return false; + case 7: + $this->debugMsg(2, "Tokenizing compression algorithm is not supported... yet?"); + return false; + case 8: + // Deflate + return $targetFileName? + file_put_contents($targetFileName, gzinflate($content, $uncompressedSize)): + gzinflate($content, $uncompressedSize); + case 9: + $this->debugMsg(2, "Enhanced Deflating is not supported... yet?"); + return false; + case 10: + $this->debugMsg(2, "PKWARE Date Compression Library Impoloding is not supported... yet?"); + return false; + case 12: + // Bzip2 + return $targetFileName? + file_put_contents($targetFileName, bzdecompress($content)): + bzdecompress($content); + case 18: + $this->debugMsg(2, "IBM TERSE is not supported... yet?"); + return false; + default: + $this->debugMsg(2, "Unknown uncompress method: $mode"); + return false; + } + } + Function debugMsg($level, $string){ + if($this->debug) + if($level == 1) + echo "dUnzip2: $string
"; + if($level == 2) + echo "dUnzip2: $string
"; + } + + Function _loadFileListByEOF(&$fh, $stopOnFile=false){ + // Check if there's a valid Central Dir signature. + // Let's consider a file comment smaller than 1024 characters... + // Actually, it length can be 65536.. But we're not going to support it. + + for($x = 0; $x < 1024; $x++){ + fseek($fh, -22-$x, SEEK_END); + + $signature = fread($fh, 4); + if($signature == $this->dirSignatureE){ + // If found EOF Central Dir + $eodir['disk_number_this'] = unpack("v", fread($fh, 2)); // number of this disk + $eodir['disk_number'] = unpack("v", fread($fh, 2)); // number of the disk with the start of the central directory + $eodir['total_entries_this'] = unpack("v", fread($fh, 2)); // total number of entries in the central dir on this disk + $eodir['total_entries'] = unpack("v", fread($fh, 2)); // total number of entries in + $eodir['size_of_cd'] = unpack("V", fread($fh, 4)); // size of the central directory + $eodir['offset_start_cd'] = unpack("V", fread($fh, 4)); // offset of start of central directory with respect to the starting disk number + $zipFileCommentLenght = unpack("v", fread($fh, 2)); // zipfile comment length + $eodir['zipfile_comment'] = $zipFileCommentLenght[1]?fread($fh, $zipFileCommentLenght[1]):''; // zipfile comment + $this->endOfCentral = Array( + 'disk_number_this'=>$eodir['disk_number_this'][1], + 'disk_number'=>$eodir['disk_number'][1], + 'total_entries_this'=>$eodir['total_entries_this'][1], + 'total_entries'=>$eodir['total_entries'][1], + 'size_of_cd'=>$eodir['size_of_cd'][1], + 'offset_start_cd'=>$eodir['offset_start_cd'][1], + 'zipfile_comment'=>$eodir['zipfile_comment'], + ); + + // Then, load file list + fseek($fh, $this->endOfCentral['offset_start_cd']); + $signature = fread($fh, 4); + + while($signature == $this->dirSignature){ + $dir['version_madeby'] = unpack("v", fread($fh, 2)); // version made by + $dir['version_needed'] = unpack("v", fread($fh, 2)); // version needed to extract + $dir['general_bit_flag'] = unpack("v", fread($fh, 2)); // general purpose bit flag + $dir['compression_method'] = unpack("v", fread($fh, 2)); // compression method + $dir['lastmod_time'] = unpack("v", fread($fh, 2)); // last mod file time + $dir['lastmod_date'] = unpack("v", fread($fh, 2)); // last mod file date + $dir['crc-32'] = fread($fh, 4); // crc-32 + $dir['compressed_size'] = unpack("V", fread($fh, 4)); // compressed size + $dir['uncompressed_size'] = unpack("V", fread($fh, 4)); // uncompressed size + $fileNameLength = unpack("v", fread($fh, 2)); // filename length + $extraFieldLength = unpack("v", fread($fh, 2)); // extra field length + $fileCommentLength = unpack("v", fread($fh, 2)); // file comment length + $dir['disk_number_start'] = unpack("v", fread($fh, 2)); // disk number start + $dir['internal_attributes'] = unpack("v", fread($fh, 2)); // internal file attributes-byte1 + $dir['external_attributes1']= unpack("v", fread($fh, 2)); // external file attributes-byte2 + $dir['external_attributes2']= unpack("v", fread($fh, 2)); // external file attributes + $dir['relative_offset'] = unpack("V", fread($fh, 4)); // relative offset of local header + $dir['file_name'] = fread($fh, $fileNameLength[1]); // filename + $dir['extra_field'] = $extraFieldLength[1] ?fread($fh, $extraFieldLength[1]) :''; // extra field + $dir['file_comment'] = $fileCommentLength[1]?fread($fh, $fileCommentLength[1]):''; // file comment + + // Convert the date and time, from MS-DOS format to UNIX Timestamp + $BINlastmod_date = str_pad(decbin($dir['lastmod_date'][1]), 16, '0', STR_PAD_LEFT); + $BINlastmod_time = str_pad(decbin($dir['lastmod_time'][1]), 16, '0', STR_PAD_LEFT); + $lastmod_dateY = bindec(substr($BINlastmod_date, 0, 7))+1980; + $lastmod_dateM = bindec(substr($BINlastmod_date, 7, 4)); + $lastmod_dateD = bindec(substr($BINlastmod_date, 11, 5)); + $lastmod_timeH = bindec(substr($BINlastmod_time, 0, 5)); + $lastmod_timeM = bindec(substr($BINlastmod_time, 5, 6)); + $lastmod_timeS = bindec(substr($BINlastmod_time, 11, 5)); + + $this->centralDirList[$dir['file_name']] = Array( + 'version_madeby'=>$dir['version_madeby'][1], + 'version_needed'=>$dir['version_needed'][1], + 'general_bit_flag'=>str_pad(decbin($dir['general_bit_flag'][1]), 8, '0', STR_PAD_LEFT), + 'compression_method'=>$dir['compression_method'][1], + 'lastmod_datetime' =>mktime($lastmod_timeH, $lastmod_timeM, $lastmod_timeS, $lastmod_dateM, $lastmod_dateD, $lastmod_dateY), + 'crc-32' =>str_pad(dechex(ord($dir['crc-32'][3])), 2, '0', STR_PAD_LEFT). + str_pad(dechex(ord($dir['crc-32'][2])), 2, '0', STR_PAD_LEFT). + str_pad(dechex(ord($dir['crc-32'][1])), 2, '0', STR_PAD_LEFT). + str_pad(dechex(ord($dir['crc-32'][0])), 2, '0', STR_PAD_LEFT), + 'compressed_size'=>$dir['compressed_size'][1], + 'uncompressed_size'=>$dir['uncompressed_size'][1], + 'disk_number_start'=>$dir['disk_number_start'][1], + 'internal_attributes'=>$dir['internal_attributes'][1], + 'external_attributes1'=>$dir['external_attributes1'][1], + 'external_attributes2'=>$dir['external_attributes2'][1], + 'relative_offset'=>$dir['relative_offset'][1], + 'file_name'=>$dir['file_name'], + 'extra_field'=>$dir['extra_field'], + 'file_comment'=>$dir['file_comment'], + ); + $signature = fread($fh, 4); + } + + // If loaded centralDirs, then try to identify the offsetPosition of the compressed data. + if($this->centralDirList) foreach($this->centralDirList as $filename=>$details){ + $i = $this->_getFileHeaderInformation($fh, $details['relative_offset']); + $this->compressedList[$filename]['file_name'] = $filename; + $this->compressedList[$filename]['compression_method'] = $details['compression_method']; + $this->compressedList[$filename]['version_needed'] = $details['version_needed']; + $this->compressedList[$filename]['lastmod_datetime'] = $details['lastmod_datetime']; + $this->compressedList[$filename]['crc-32'] = $details['crc-32']; + $this->compressedList[$filename]['compressed_size'] = $details['compressed_size']; + $this->compressedList[$filename]['uncompressed_size'] = $details['uncompressed_size']; + $this->compressedList[$filename]['lastmod_datetime'] = $details['lastmod_datetime']; + $this->compressedList[$filename]['extra_field'] = $i['extra_field']; + $this->compressedList[$filename]['contents-startOffset']=$i['contents-startOffset']; + if(strtolower($stopOnFile) == strtolower($filename)) + break; + } + return true; + } + } + return false; + } + Function _loadFileListBySignatures(&$fh, $stopOnFile=false){ + fseek($fh, 0); + + $return = false; + for(;;){ + $details = $this->_getFileHeaderInformation($fh); + if(!$details){ + $this->debugMsg(1, "Invalid signature. Trying to verify if is old style Data Descriptor..."); + fseek($fh, 12 - 4, SEEK_CUR); // 12: Data descriptor - 4: Signature (that will be read again) + $details = $this->_getFileHeaderInformation($fh); + } + if(!$details){ + $this->debugMsg(1, "Still invalid signature. Probably reached the end of the file."); + break; + } + $filename = $details['file_name']; + $this->compressedList[$filename] = $details; + $return = true; + if(strtolower($stopOnFile) == strtolower($filename)) + break; + } + + return $return; + } + Function _getFileHeaderInformation(&$fh, $startOffset=false){ + if($startOffset !== false) + fseek($fh, $startOffset); + + $signature = fread($fh, 4); + if($signature == $this->zipSignature){ + # $this->debugMsg(1, "Zip Signature!"); + + // Get information about the zipped file + $file['version_needed'] = unpack("v", fread($fh, 2)); // version needed to extract + $file['general_bit_flag'] = unpack("v", fread($fh, 2)); // general purpose bit flag + $file['compression_method'] = unpack("v", fread($fh, 2)); // compression method + $file['lastmod_time'] = unpack("v", fread($fh, 2)); // last mod file time + $file['lastmod_date'] = unpack("v", fread($fh, 2)); // last mod file date + $file['crc-32'] = fread($fh, 4); // crc-32 + $file['compressed_size'] = unpack("V", fread($fh, 4)); // compressed size + $file['uncompressed_size'] = unpack("V", fread($fh, 4)); // uncompressed size + $fileNameLength = unpack("v", fread($fh, 2)); // filename length + $extraFieldLength = unpack("v", fread($fh, 2)); // extra field length + $file['file_name'] = fread($fh, $fileNameLength[1]); // filename + $file['extra_field'] = $extraFieldLength[1]?fread($fh, $extraFieldLength[1]):''; // extra field + $file['contents-startOffset']= ftell($fh); + + // Bypass the whole compressed contents, and look for the next file + fseek($fh, $file['compressed_size'][1], SEEK_CUR); + + // Convert the date and time, from MS-DOS format to UNIX Timestamp + $BINlastmod_date = str_pad(decbin($file['lastmod_date'][1]), 16, '0', STR_PAD_LEFT); + $BINlastmod_time = str_pad(decbin($file['lastmod_time'][1]), 16, '0', STR_PAD_LEFT); + $lastmod_dateY = bindec(substr($BINlastmod_date, 0, 7))+1980; + $lastmod_dateM = bindec(substr($BINlastmod_date, 7, 4)); + $lastmod_dateD = bindec(substr($BINlastmod_date, 11, 5)); + $lastmod_timeH = bindec(substr($BINlastmod_time, 0, 5)); + $lastmod_timeM = bindec(substr($BINlastmod_time, 5, 6)); + $lastmod_timeS = bindec(substr($BINlastmod_time, 11, 5)); + + // Mount file table + $i = Array( + 'file_name' =>$file['file_name'], + 'compression_method'=>$file['compression_method'][1], + 'version_needed' =>$file['version_needed'][1], + 'lastmod_datetime' =>mktime($lastmod_timeH, $lastmod_timeM, $lastmod_timeS, $lastmod_dateM, $lastmod_dateD, $lastmod_dateY), + 'crc-32' =>str_pad(dechex(ord($file['crc-32'][3])), 2, '0', STR_PAD_LEFT). + str_pad(dechex(ord($file['crc-32'][2])), 2, '0', STR_PAD_LEFT). + str_pad(dechex(ord($file['crc-32'][1])), 2, '0', STR_PAD_LEFT). + str_pad(dechex(ord($file['crc-32'][0])), 2, '0', STR_PAD_LEFT), + 'compressed_size' =>$file['compressed_size'][1], + 'uncompressed_size' =>$file['uncompressed_size'][1], + 'extra_field' =>$file['extra_field'], + 'general_bit_flag' =>str_pad(decbin($file['general_bit_flag'][1]), 8, '0', STR_PAD_LEFT), + 'contents-startOffset'=>$file['contents-startOffset'] + ); + return $i; + } + return false; + } +} +?> diff --git a/oss/vtiger/trunk/vtlib/thirdparty/dZip.inc.php b/oss/vtiger/trunk/vtlib/thirdparty/dZip.inc.php new file mode 100644 index 00000000..3ca05cfb --- /dev/null +++ b/oss/vtiger/trunk/vtlib/thirdparty/dZip.inc.php @@ -0,0 +1,153 @@ + +filename = $filename; + $this->overwrite = $overwrite; + } + Function addDir($dirname, $fileComments=''){ + if(substr($dirname, -1) != '/') + $dirname .= '/'; + $this->addFile(false, $dirname, $fileComments); + } + Function addFile($filename, $cfilename, $fileComments='', $data=false){ + if(!($fh = &$this->fh)) + $fh = fopen($this->filename, $this->overwrite?'wb':'a+b'); + + // $filename can be a local file OR the data wich will be compressed + if(substr($cfilename, -1)=='/'){ + $details['uncsize'] = 0; + $data = ''; + } + elseif(file_exists($filename)){ + $details['uncsize'] = filesize($filename); + $data = file_get_contents($filename); + } + elseif($filename){ + echo "Cannot add $filename. File not found
"; + return false; + } + else{ + $details['uncsize'] = strlen($data); // Prasad: Fixed instead of strlen($filename) + // DATA is given.. use it! :| + } + + // if data to compress is too small, just store it + if($details['uncsize'] < 256){ + $details['comsize'] = $details['uncsize']; + $details['vneeded'] = 10; + $details['cmethod'] = 0; + $zdata = &$data; + } + else{ // otherwise, compress it + $zdata = gzcompress($data); + $zdata = substr(substr($zdata, 0, strlen($zdata) - 4), 2); // fix crc bug (thanks to Eric Mueller) + $details['comsize'] = strlen($zdata); + $details['vneeded'] = 10; + $details['cmethod'] = 8; + } + + $details['bitflag'] = 0; + $details['crc_32'] = crc32($data); + + // Convert date and time to DOS Format, and set then + $lastmod_timeS = str_pad(decbin(date('s')>=32?date('s')-32:date('s')), 5, '0', STR_PAD_LEFT); + $lastmod_timeM = str_pad(decbin(date('i')), 6, '0', STR_PAD_LEFT); + $lastmod_timeH = str_pad(decbin(date('H')), 5, '0', STR_PAD_LEFT); + $lastmod_dateD = str_pad(decbin(date('d')), 5, '0', STR_PAD_LEFT); + $lastmod_dateM = str_pad(decbin(date('m')), 4, '0', STR_PAD_LEFT); + $lastmod_dateY = str_pad(decbin(date('Y')-1980), 7, '0', STR_PAD_LEFT); + + # echo "ModTime: $lastmod_timeS-$lastmod_timeM-$lastmod_timeH (".date("s H H").")\n"; + # echo "ModDate: $lastmod_dateD-$lastmod_dateM-$lastmod_dateY (".date("d m Y").")\n"; + $details['modtime'] = bindec("$lastmod_timeH$lastmod_timeM$lastmod_timeS"); + $details['moddate'] = bindec("$lastmod_dateY$lastmod_dateM$lastmod_dateD"); + + $details['offset'] = ftell($fh); + fwrite($fh, $this->zipSignature); + fwrite($fh, pack('s', $details['vneeded'])); // version_needed + fwrite($fh, pack('s', $details['bitflag'])); // general_bit_flag + fwrite($fh, pack('s', $details['cmethod'])); // compression_method + fwrite($fh, pack('s', $details['modtime'])); // lastmod_time + fwrite($fh, pack('s', $details['moddate'])); // lastmod_date + fwrite($fh, pack('V', $details['crc_32'])); // crc-32 + fwrite($fh, pack('I', $details['comsize'])); // compressed_size + fwrite($fh, pack('I', $details['uncsize'])); // uncompressed_size + fwrite($fh, pack('s', strlen($cfilename))); // file_name_length + fwrite($fh, pack('s', 0)); // extra_field_length + fwrite($fh, $cfilename); // file_name + // ignoring extra_field + fwrite($fh, $zdata); + + // Append it to central dir + $details['external_attributes'] = (substr($cfilename, -1)=='/'&&!$zdata)?16:32; // Directory or file name + $details['comments'] = $fileComments; + $this->appendCentralDir($cfilename, $details); + $this->files_count++; + } + Function setExtra($filename, $property, $value){ + $this->centraldirs[$filename][$property] = $value; + } + Function save($zipComments=''){ + if(!($fh = &$this->fh)) + $fh = fopen($this->filename, $this->overwrite?'w':'a+'); + + $cdrec = ""; + foreach($this->centraldirs as $filename=>$cd){ + $cdrec .= $this->dirSignature; + $cdrec .= "\x0\x0"; // version made by + $cdrec .= pack('v', $cd['vneeded']); // version needed to extract + $cdrec .= "\x0\x0"; // general bit flag + $cdrec .= pack('v', $cd['cmethod']); // compression method + $cdrec .= pack('v', $cd['modtime']); // lastmod time + $cdrec .= pack('v', $cd['moddate']); // lastmod date + $cdrec .= pack('V', $cd['crc_32']); // crc32 + $cdrec .= pack('V', $cd['comsize']); // compressed filesize + $cdrec .= pack('V', $cd['uncsize']); // uncompressed filesize + $cdrec .= pack('v', strlen($filename)); // file comment length + $cdrec .= pack('v', 0); // extra field length + $cdrec .= pack('v', strlen($cd['comments'])); // file comment length + $cdrec .= pack('v', 0); // disk number start + $cdrec .= pack('v', 0); // internal file attributes + $cdrec .= pack('V', $cd['external_attributes']); // internal file attributes + $cdrec .= pack('V', $cd['offset']); // relative offset of local header + $cdrec .= $filename; + $cdrec .= $cd['comments']; + } + $before_cd = ftell($fh); + fwrite($fh, $cdrec); + + // end of central dir + fwrite($fh, $this->dirSignatureE); + fwrite($fh, pack('v', 0)); // number of this disk + fwrite($fh, pack('v', 0)); // number of the disk with the start of the central directory + fwrite($fh, pack('v', $this->files_count)); // total # of entries "on this disk" + fwrite($fh, pack('v', $this->files_count)); // total # of entries overall + fwrite($fh, pack('V', strlen($cdrec))); // size of central dir + fwrite($fh, pack('V', $before_cd)); // offset to start of central dir + fwrite($fh, pack('v', strlen($zipComments))); // .zip file comment length + fwrite($fh, $zipComments); + + fclose($fh); + } + + // Private + Function appendCentralDir($filename,$properties){ + $this->centraldirs[$filename] = $properties; + } +} +?> diff --git a/oss/vtiger/trunk/vtlib/thirdparty/network/Net/Socket.php b/oss/vtiger/trunk/vtlib/thirdparty/network/Net/Socket.php new file mode 100644 index 00000000..953f422d --- /dev/null +++ b/oss/vtiger/trunk/vtlib/thirdparty/network/Net/Socket.php @@ -0,0 +1,592 @@ + | +// | Chuck Hagenbuch | +// +----------------------------------------------------------------------+ +// +// $Id: Socket.php,v 1.38 2008/02/15 18:24:17 chagenbu Exp $ + +require_once dirname(__FILE__) . '/../PEAR.php'; + +define('NET_SOCKET_READ', 1); +define('NET_SOCKET_WRITE', 2); +define('NET_SOCKET_ERROR', 4); + +/** + * Generalized Socket class. + * + * @version 1.1 + * @author Stig Bakken + * @author Chuck Hagenbuch + */ +class Net_Socket extends PEAR { + + /** + * Socket file pointer. + * @var resource $fp + */ + var $fp = null; + + /** + * Whether the socket is blocking. Defaults to true. + * @var boolean $blocking + */ + var $blocking = true; + + /** + * Whether the socket is persistent. Defaults to false. + * @var boolean $persistent + */ + var $persistent = false; + + /** + * The IP address to connect to. + * @var string $addr + */ + var $addr = ''; + + /** + * The port number to connect to. + * @var integer $port + */ + var $port = 0; + + /** + * Number of seconds to wait on socket connections before assuming + * there's no more data. Defaults to no timeout. + * @var integer $timeout + */ + var $timeout = false; + + /** + * Number of bytes to read at a time in readLine() and + * readAll(). Defaults to 2048. + * @var integer $lineLength + */ + var $lineLength = 2048; + + /** + * Connect to the specified port. If called when the socket is + * already connected, it disconnects and connects again. + * + * @param string $addr IP address or host name. + * @param integer $port TCP port number. + * @param boolean $persistent (optional) Whether the connection is + * persistent (kept open between requests + * by the web server). + * @param integer $timeout (optional) How long to wait for data. + * @param array $options See options for stream_context_create. + * + * @access public + * + * @return boolean | PEAR_Error True on success or a PEAR_Error on failure. + */ + function connect($addr, $port = 0, $persistent = null, $timeout = null, $options = null) + { + if (is_resource($this->fp)) { + @fclose($this->fp); + $this->fp = null; + } + + if (!$addr) { + return $this->raiseError('$addr cannot be empty'); + } elseif (strspn($addr, '.0123456789') == strlen($addr) || + strstr($addr, '/') !== false) { + $this->addr = $addr; + } else { + $this->addr = @gethostbyname($addr); + } + + $this->port = $port % 65536; + + if ($persistent !== null) { + $this->persistent = $persistent; + } + + if ($timeout !== null) { + $this->timeout = $timeout; + } + + $openfunc = $this->persistent ? 'pfsockopen' : 'fsockopen'; + $errno = 0; + $errstr = ''; + $old_track_errors = @ini_set('track_errors', 1); + if ($options && function_exists('stream_context_create')) { + if ($this->timeout) { + $timeout = $this->timeout; + } else { + $timeout = 0; + } + $context = stream_context_create($options); + + // Since PHP 5 fsockopen doesn't allow context specification + if (function_exists('stream_socket_client')) { + $flags = $this->persistent ? STREAM_CLIENT_PERSISTENT : STREAM_CLIENT_CONNECT; + $addr = $this->addr . ':' . $this->port; + $fp = stream_socket_client($addr, $errno, $errstr, $timeout, $flags, $context); + } else { + $fp = @$openfunc($this->addr, $this->port, $errno, $errstr, $timeout, $context); + } + } else { + if ($this->timeout) { + $fp = @$openfunc($this->addr, $this->port, $errno, $errstr, $this->timeout); + } else { + $fp = @$openfunc($this->addr, $this->port, $errno, $errstr); + } + } + + if (!$fp) { + if ($errno == 0 && isset($php_errormsg)) { + $errstr = $php_errormsg; + } + @ini_set('track_errors', $old_track_errors); + return $this->raiseError($errstr, $errno); + } + + @ini_set('track_errors', $old_track_errors); + $this->fp = $fp; + + return $this->setBlocking($this->blocking); + } + + /** + * Disconnects from the peer, closes the socket. + * + * @access public + * @return mixed true on success or a PEAR_Error instance otherwise + */ + function disconnect() + { + if (!is_resource($this->fp)) { + return $this->raiseError('not connected'); + } + + @fclose($this->fp); + $this->fp = null; + return true; + } + + /** + * Find out if the socket is in blocking mode. + * + * @access public + * @return boolean The current blocking mode. + */ + function isBlocking() + { + return $this->blocking; + } + + /** + * Sets whether the socket connection should be blocking or + * not. A read call to a non-blocking socket will return immediately + * if there is no data available, whereas it will block until there + * is data for blocking sockets. + * + * @param boolean $mode True for blocking sockets, false for nonblocking. + * @access public + * @return mixed true on success or a PEAR_Error instance otherwise + */ + function setBlocking($mode) + { + if (!is_resource($this->fp)) { + return $this->raiseError('not connected'); + } + + $this->blocking = $mode; + socket_set_blocking($this->fp, $this->blocking); + return true; + } + + /** + * Sets the timeout value on socket descriptor, + * expressed in the sum of seconds and microseconds + * + * @param integer $seconds Seconds. + * @param integer $microseconds Microseconds. + * @access public + * @return mixed true on success or a PEAR_Error instance otherwise + */ + function setTimeout($seconds, $microseconds) + { + if (!is_resource($this->fp)) { + return $this->raiseError('not connected'); + } + + return socket_set_timeout($this->fp, $seconds, $microseconds); + } + + /** + * Sets the file buffering size on the stream. + * See php's stream_set_write_buffer for more information. + * + * @param integer $size Write buffer size. + * @access public + * @return mixed on success or an PEAR_Error object otherwise + */ + function setWriteBuffer($size) + { + if (!is_resource($this->fp)) { + return $this->raiseError('not connected'); + } + + $returned = stream_set_write_buffer($this->fp, $size); + if ($returned == 0) { + return true; + } + return $this->raiseError('Cannot set write buffer.'); + } + + /** + * Returns information about an existing socket resource. + * Currently returns four entries in the result array: + * + *

+ * timed_out (bool) - The socket timed out waiting for data
+ * blocked (bool) - The socket was blocked
+ * eof (bool) - Indicates EOF event
+ * unread_bytes (int) - Number of bytes left in the socket buffer
+ *

+ * + * @access public + * @return mixed Array containing information about existing socket resource or a PEAR_Error instance otherwise + */ + function getStatus() + { + if (!is_resource($this->fp)) { + return $this->raiseError('not connected'); + } + + return socket_get_status($this->fp); + } + + /** + * Get a specified line of data + * + * @access public + * @return $size bytes of data from the socket, or a PEAR_Error if + * not connected. + */ + function gets($size) + { + if (!is_resource($this->fp)) { + return $this->raiseError('not connected'); + } + + return @fgets($this->fp, $size); + } + + /** + * Read a specified amount of data. This is guaranteed to return, + * and has the added benefit of getting everything in one fread() + * chunk; if you know the size of the data you're getting + * beforehand, this is definitely the way to go. + * + * @param integer $size The number of bytes to read from the socket. + * @access public + * @return $size bytes of data from the socket, or a PEAR_Error if + * not connected. + */ + function read($size) + { + if (!is_resource($this->fp)) { + return $this->raiseError('not connected'); + } + + return @fread($this->fp, $size); + } + + /** + * Write a specified amount of data. + * + * @param string $data Data to write. + * @param integer $blocksize Amount of data to write at once. + * NULL means all at once. + * + * @access public + * @return mixed If the socket is not connected, returns an instance of PEAR_Error + * If the write succeeds, returns the number of bytes written + * If the write fails, returns false. + */ + function write($data, $blocksize = null) + { + if (!is_resource($this->fp)) { + return $this->raiseError('not connected'); + } + + if (is_null($blocksize) && !OS_WINDOWS) { + return @fwrite($this->fp, $data); + } else { + if (is_null($blocksize)) { + $blocksize = 1024; + } + + $pos = 0; + $size = strlen($data); + while ($pos < $size) { + $written = @fwrite($this->fp, substr($data, $pos, $blocksize)); + if ($written === false) { + return false; + } + $pos += $written; + } + + return $pos; + } + } + + /** + * Write a line of data to the socket, followed by a trailing "\r\n". + * + * @access public + * @return mixed fputs result, or an error + */ + function writeLine($data) + { + if (!is_resource($this->fp)) { + return $this->raiseError('not connected'); + } + + return fwrite($this->fp, $data . "\r\n"); + } + + /** + * Tests for end-of-file on a socket descriptor. + * + * Also returns true if the socket is disconnected. + * + * @access public + * @return bool + */ + function eof() + { + return (!is_resource($this->fp) || feof($this->fp)); + } + + /** + * Reads a byte of data + * + * @access public + * @return 1 byte of data from the socket, or a PEAR_Error if + * not connected. + */ + function readByte() + { + if (!is_resource($this->fp)) { + return $this->raiseError('not connected'); + } + + return ord(@fread($this->fp, 1)); + } + + /** + * Reads a word of data + * + * @access public + * @return 1 word of data from the socket, or a PEAR_Error if + * not connected. + */ + function readWord() + { + if (!is_resource($this->fp)) { + return $this->raiseError('not connected'); + } + + $buf = @fread($this->fp, 2); + return (ord($buf[0]) + (ord($buf[1]) << 8)); + } + + /** + * Reads an int of data + * + * @access public + * @return integer 1 int of data from the socket, or a PEAR_Error if + * not connected. + */ + function readInt() + { + if (!is_resource($this->fp)) { + return $this->raiseError('not connected'); + } + + $buf = @fread($this->fp, 4); + return (ord($buf[0]) + (ord($buf[1]) << 8) + + (ord($buf[2]) << 16) + (ord($buf[3]) << 24)); + } + + /** + * Reads a zero-terminated string of data + * + * @access public + * @return string, or a PEAR_Error if + * not connected. + */ + function readString() + { + if (!is_resource($this->fp)) { + return $this->raiseError('not connected'); + } + + $string = ''; + while (($char = @fread($this->fp, 1)) != "\x00") { + $string .= $char; + } + return $string; + } + + /** + * Reads an IP Address and returns it in a dot formatted string + * + * @access public + * @return Dot formatted string, or a PEAR_Error if + * not connected. + */ + function readIPAddress() + { + if (!is_resource($this->fp)) { + return $this->raiseError('not connected'); + } + + $buf = @fread($this->fp, 4); + return sprintf('%d.%d.%d.%d', ord($buf[0]), ord($buf[1]), + ord($buf[2]), ord($buf[3])); + } + + /** + * Read until either the end of the socket or a newline, whichever + * comes first. Strips the trailing newline from the returned data. + * + * @access public + * @return All available data up to a newline, without that + * newline, or until the end of the socket, or a PEAR_Error if + * not connected. + */ + function readLine() + { + if (!is_resource($this->fp)) { + return $this->raiseError('not connected'); + } + + $line = ''; + $timeout = time() + $this->timeout; + while (!feof($this->fp) && (!$this->timeout || time() < $timeout)) { + $line .= @fgets($this->fp, $this->lineLength); + if (substr($line, -1) == "\n") { + return rtrim($line, "\r\n"); + } + } + return $line; + } + + /** + * Read until the socket closes, or until there is no more data in + * the inner PHP buffer. If the inner buffer is empty, in blocking + * mode we wait for at least 1 byte of data. Therefore, in + * blocking mode, if there is no data at all to be read, this + * function will never exit (unless the socket is closed on the + * remote end). + * + * @access public + * + * @return string All data until the socket closes, or a PEAR_Error if + * not connected. + */ + function readAll() + { + if (!is_resource($this->fp)) { + return $this->raiseError('not connected'); + } + + $data = ''; + while (!feof($this->fp)) { + $data .= @fread($this->fp, $this->lineLength); + } + return $data; + } + + /** + * Runs the equivalent of the select() system call on the socket + * with a timeout specified by tv_sec and tv_usec. + * + * @param integer $state Which of read/write/error to check for. + * @param integer $tv_sec Number of seconds for timeout. + * @param integer $tv_usec Number of microseconds for timeout. + * + * @access public + * @return False if select fails, integer describing which of read/write/error + * are ready, or PEAR_Error if not connected. + */ + function select($state, $tv_sec, $tv_usec = 0) + { + if (!is_resource($this->fp)) { + return $this->raiseError('not connected'); + } + + $read = null; + $write = null; + $except = null; + if ($state & NET_SOCKET_READ) { + $read[] = $this->fp; + } + if ($state & NET_SOCKET_WRITE) { + $write[] = $this->fp; + } + if ($state & NET_SOCKET_ERROR) { + $except[] = $this->fp; + } + if (false === ($sr = stream_select($read, $write, $except, $tv_sec, $tv_usec))) { + return false; + } + + $result = 0; + if (count($read)) { + $result |= NET_SOCKET_READ; + } + if (count($write)) { + $result |= NET_SOCKET_WRITE; + } + if (count($except)) { + $result |= NET_SOCKET_ERROR; + } + return $result; + } + + /** + * Turns encryption on/off on a connected socket. + * + * @param bool $enabled Set this parameter to true to enable encryption + * and false to disable encryption. + * @param integer $type Type of encryption. See + * http://se.php.net/manual/en/function.stream-socket-enable-crypto.php for values. + * + * @access public + * @return false on error, true on success and 0 if there isn't enough data and the + * user should try again (non-blocking sockets only). A PEAR_Error object + * is returned if the socket is not connected + */ + function enableCrypto($enabled, $type) + { + if (version_compare(phpversion(), "5.1.0", ">=")) { + if (!is_resource($this->fp)) { + return $this->raiseError('not connected'); + } + return @stream_socket_enable_crypto($this->fp, $enabled, $type); + } else { + return $this->raiseError('Net_Socket::enableCrypto() requires php version >= 5.1.0'); + } + } + +} diff --git a/oss/vtiger/trunk/vtlib/thirdparty/network/Net/URL.php b/oss/vtiger/trunk/vtlib/thirdparty/network/Net/URL.php new file mode 100644 index 00000000..3dcfef60 --- /dev/null +++ b/oss/vtiger/trunk/vtlib/thirdparty/network/Net/URL.php @@ -0,0 +1,485 @@ + | +// +-----------------------------------------------------------------------+ +// +// $Id: URL.php,v 1.49 2007/06/28 14:43:07 davidc Exp $ +// +// Net_URL Class + + +class Net_URL +{ + var $options = array('encode_query_keys' => false); + /** + * Full url + * @var string + */ + var $url; + + /** + * Protocol + * @var string + */ + var $protocol; + + /** + * Username + * @var string + */ + var $username; + + /** + * Password + * @var string + */ + var $password; + + /** + * Host + * @var string + */ + var $host; + + /** + * Port + * @var integer + */ + var $port; + + /** + * Path + * @var string + */ + var $path; + + /** + * Query string + * @var array + */ + var $querystring; + + /** + * Anchor + * @var string + */ + var $anchor; + + /** + * Whether to use [] + * @var bool + */ + var $useBrackets; + + /** + * PHP4 Constructor + * + * @see __construct() + */ + function Net_URL($url = null, $useBrackets = true) + { + $this->__construct($url, $useBrackets); + } + + /** + * PHP5 Constructor + * + * Parses the given url and stores the various parts + * Defaults are used in certain cases + * + * @param string $url Optional URL + * @param bool $useBrackets Whether to use square brackets when + * multiple querystrings with the same name + * exist + */ + function __construct($url = null, $useBrackets = true) + { + $this->url = $url; + $this->useBrackets = $useBrackets; + + $this->initialize(); + } + + function initialize() + { + $HTTP_SERVER_VARS = !empty($_SERVER) ? $_SERVER : $GLOBALS['HTTP_SERVER_VARS']; + + $this->user = ''; + $this->pass = ''; + $this->host = ''; + $this->port = 80; + $this->path = ''; + $this->querystring = array(); + $this->anchor = ''; + + // Only use defaults if not an absolute URL given + if (!preg_match('/^[a-z0-9]+:\/\//i', $this->url)) { + $this->protocol = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on' ? 'https' : 'http'); + + /** + * Figure out host/port + */ + if (!empty($HTTP_SERVER_VARS['HTTP_HOST']) && + preg_match('/^(.*)(:([0-9]+))?$/U', $HTTP_SERVER_VARS['HTTP_HOST'], $matches)) + { + $host = $matches[1]; + if (!empty($matches[3])) { + $port = $matches[3]; + } else { + $port = $this->getStandardPort($this->protocol); + } + } + + $this->user = ''; + $this->pass = ''; + $this->host = !empty($host) ? $host : (isset($HTTP_SERVER_VARS['SERVER_NAME']) ? $HTTP_SERVER_VARS['SERVER_NAME'] : 'localhost'); + $this->port = !empty($port) ? $port : (isset($HTTP_SERVER_VARS['SERVER_PORT']) ? $HTTP_SERVER_VARS['SERVER_PORT'] : $this->getStandardPort($this->protocol)); + $this->path = !empty($HTTP_SERVER_VARS['PHP_SELF']) ? $HTTP_SERVER_VARS['PHP_SELF'] : '/'; + $this->querystring = isset($HTTP_SERVER_VARS['QUERY_STRING']) ? $this->_parseRawQuerystring($HTTP_SERVER_VARS['QUERY_STRING']) : null; + $this->anchor = ''; + } + + // Parse the url and store the various parts + if (!empty($this->url)) { + $urlinfo = parse_url($this->url); + + // Default querystring + $this->querystring = array(); + + foreach ($urlinfo as $key => $value) { + switch ($key) { + case 'scheme': + $this->protocol = $value; + $this->port = $this->getStandardPort($value); + break; + + case 'user': + case 'pass': + case 'host': + case 'port': + $this->$key = $value; + break; + + case 'path': + if ($value{0} == '/') { + $this->path = $value; + } else { + $path = dirname($this->path) == DIRECTORY_SEPARATOR ? '' : dirname($this->path); + $this->path = sprintf('%s/%s', $path, $value); + } + break; + + case 'query': + $this->querystring = $this->_parseRawQueryString($value); + break; + + case 'fragment': + $this->anchor = $value; + break; + } + } + } + } + /** + * Returns full url + * + * @return string Full url + * @access public + */ + function getURL() + { + $querystring = $this->getQueryString(); + + $this->url = $this->protocol . '://' + . $this->user . (!empty($this->pass) ? ':' : '') + . $this->pass . (!empty($this->user) ? '@' : '') + . $this->host . ($this->port == $this->getStandardPort($this->protocol) ? '' : ':' . $this->port) + . $this->path + . (!empty($querystring) ? '?' . $querystring : '') + . (!empty($this->anchor) ? '#' . $this->anchor : ''); + + return $this->url; + } + + /** + * Adds or updates a querystring item (URL parameter). + * Automatically encodes parameters with rawurlencode() if $preencoded + * is false. + * You can pass an array to $value, it gets mapped via [] in the URL if + * $this->useBrackets is activated. + * + * @param string $name Name of item + * @param string $value Value of item + * @param bool $preencoded Whether value is urlencoded or not, default = not + * @access public + */ + function addQueryString($name, $value, $preencoded = false) + { + if ($this->getOption('encode_query_keys')) { + $name = rawurlencode($name); + } + + if ($preencoded) { + $this->querystring[$name] = $value; + } else { + $this->querystring[$name] = is_array($value) ? array_map('rawurlencode', $value): rawurlencode($value); + } + } + + /** + * Removes a querystring item + * + * @param string $name Name of item + * @access public + */ + function removeQueryString($name) + { + if ($this->getOption('encode_query_keys')) { + $name = rawurlencode($name); + } + + if (isset($this->querystring[$name])) { + unset($this->querystring[$name]); + } + } + + /** + * Sets the querystring to literally what you supply + * + * @param string $querystring The querystring data. Should be of the format foo=bar&x=y etc + * @access public + */ + function addRawQueryString($querystring) + { + $this->querystring = $this->_parseRawQueryString($querystring); + } + + /** + * Returns flat querystring + * + * @return string Querystring + * @access public + */ + function getQueryString() + { + if (!empty($this->querystring)) { + foreach ($this->querystring as $name => $value) { + // Encode var name + $name = rawurlencode($name); + + if (is_array($value)) { + foreach ($value as $k => $v) { + $querystring[] = $this->useBrackets ? sprintf('%s[%s]=%s', $name, $k, $v) : ($name . '=' . $v); + } + } elseif (!is_null($value)) { + $querystring[] = $name . '=' . $value; + } else { + $querystring[] = $name; + } + } + $querystring = implode(ini_get('arg_separator.output'), $querystring); + } else { + $querystring = ''; + } + + return $querystring; + } + + /** + * Parses raw querystring and returns an array of it + * + * @param string $querystring The querystring to parse + * @return array An array of the querystring data + * @access private + */ + function _parseRawQuerystring($querystring) + { + $parts = preg_split('/[' . preg_quote(ini_get('arg_separator.input'), '/') . ']/', $querystring, -1, PREG_SPLIT_NO_EMPTY); + $return = array(); + + foreach ($parts as $part) { + if (strpos($part, '=') !== false) { + $value = substr($part, strpos($part, '=') + 1); + $key = substr($part, 0, strpos($part, '=')); + } else { + $value = null; + $key = $part; + } + + if (!$this->getOption('encode_query_keys')) { + $key = rawurldecode($key); + } + + if (preg_match('#^(.*)\[([0-9a-z_-]*)\]#i', $key, $matches)) { + $key = $matches[1]; + $idx = $matches[2]; + + // Ensure is an array + if (empty($return[$key]) || !is_array($return[$key])) { + $return[$key] = array(); + } + + // Add data + if ($idx === '') { + $return[$key][] = $value; + } else { + $return[$key][$idx] = $value; + } + } elseif (!$this->useBrackets AND !empty($return[$key])) { + $return[$key] = (array)$return[$key]; + $return[$key][] = $value; + } else { + $return[$key] = $value; + } + } + + return $return; + } + + /** + * Resolves //, ../ and ./ from a path and returns + * the result. Eg: + * + * /foo/bar/../boo.php => /foo/boo.php + * /foo/bar/../../boo.php => /boo.php + * /foo/bar/.././/boo.php => /foo/boo.php + * + * This method can also be called statically. + * + * @param string $path URL path to resolve + * @return string The result + */ + function resolvePath($path) + { + $path = explode('/', str_replace('//', '/', $path)); + + for ($i=0; $i 1 OR ($i == 1 AND $path[0] != '') ) ) { + unset($path[$i]); + unset($path[$i-1]); + $path = array_values($path); + $i -= 2; + + } elseif ($path[$i] == '..' AND $i == 1 AND $path[0] == '') { + unset($path[$i]); + $path = array_values($path); + $i--; + + } else { + continue; + } + } + + return implode('/', $path); + } + + /** + * Returns the standard port number for a protocol + * + * @param string $scheme The protocol to lookup + * @return integer Port number or NULL if no scheme matches + * + * @author Philippe Jausions + */ + function getStandardPort($scheme) + { + switch (strtolower($scheme)) { + case 'http': return 80; + case 'https': return 443; + case 'ftp': return 21; + case 'imap': return 143; + case 'imaps': return 993; + case 'pop3': return 110; + case 'pop3s': return 995; + default: return null; + } + } + + /** + * Forces the URL to a particular protocol + * + * @param string $protocol Protocol to force the URL to + * @param integer $port Optional port (standard port is used by default) + */ + function setProtocol($protocol, $port = null) + { + $this->protocol = $protocol; + $this->port = is_null($port) ? $this->getStandardPort($protocol) : $port; + } + + /** + * Set an option + * + * This function set an option + * to be used thorough the script. + * + * @access public + * @param string $optionName The optionname to set + * @param string $value The value of this option. + */ + function setOption($optionName, $value) + { + if (!array_key_exists($optionName, $this->options)) { + return false; + } + + $this->options[$optionName] = $value; + $this->initialize(); + } + + /** + * Get an option + * + * This function gets an option + * from the $this->options array + * and return it's value. + * + * @access public + * @param string $opionName The name of the option to retrieve + * @see $this->options + */ + function getOption($optionName) + { + if (!isset($this->options[$optionName])) { + return false; + } + + return $this->options[$optionName]; + } + +} +?> diff --git a/oss/vtiger/trunk/vtlib/thirdparty/network/PEAR.php b/oss/vtiger/trunk/vtlib/thirdparty/network/PEAR.php new file mode 100644 index 00000000..4c24c600 --- /dev/null +++ b/oss/vtiger/trunk/vtlib/thirdparty/network/PEAR.php @@ -0,0 +1,1118 @@ + + * @author Stig Bakken + * @author Tomas V.V.Cox + * @author Greg Beaver + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version CVS: $Id: PEAR.php,v 1.104 2008/01/03 20:26:34 cellog Exp $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 0.1 + */ + +/**#@+ + * ERROR constants + */ +define('PEAR_ERROR_RETURN', 1); +define('PEAR_ERROR_PRINT', 2); +define('PEAR_ERROR_TRIGGER', 4); +define('PEAR_ERROR_DIE', 8); +define('PEAR_ERROR_CALLBACK', 16); +/** + * WARNING: obsolete + * @deprecated + */ +define('PEAR_ERROR_EXCEPTION', 32); +/**#@-*/ +define('PEAR_ZE2', (function_exists('version_compare') && + version_compare(zend_version(), "2-dev", "ge"))); + +if (substr(PHP_OS, 0, 3) == 'WIN') { + define('OS_WINDOWS', true); + define('OS_UNIX', false); + define('PEAR_OS', 'Windows'); +} else { + define('OS_WINDOWS', false); + define('OS_UNIX', true); + define('PEAR_OS', 'Unix'); // blatant assumption +} + +// instant backwards compatibility +if (!defined('PATH_SEPARATOR')) { + if (OS_WINDOWS) { + define('PATH_SEPARATOR', ';'); + } else { + define('PATH_SEPARATOR', ':'); + } +} + +$GLOBALS['_PEAR_default_error_mode'] = PEAR_ERROR_RETURN; +$GLOBALS['_PEAR_default_error_options'] = E_USER_NOTICE; +$GLOBALS['_PEAR_destructor_object_list'] = array(); +$GLOBALS['_PEAR_shutdown_funcs'] = array(); +$GLOBALS['_PEAR_error_handler_stack'] = array(); + +@ini_set('track_errors', true); + +/** + * Base class for other PEAR classes. Provides rudimentary + * emulation of destructors. + * + * If you want a destructor in your class, inherit PEAR and make a + * destructor method called _yourclassname (same name as the + * constructor, but with a "_" prefix). Also, in your constructor you + * have to call the PEAR constructor: $this->PEAR();. + * The destructor method will be called without parameters. Note that + * at in some SAPI implementations (such as Apache), any output during + * the request shutdown (in which destructors are called) seems to be + * discarded. If you need to get any debug information from your + * destructor, use error_log(), syslog() or something similar. + * + * IMPORTANT! To use the emulated destructors you need to create the + * objects by reference: $obj =& new PEAR_child; + * + * @category pear + * @package PEAR + * @author Stig Bakken + * @author Tomas V.V. Cox + * @author Greg Beaver + * @copyright 1997-2006 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version Release: 1.7.2 + * @link http://pear.php.net/package/PEAR + * @see PEAR_Error + * @since Class available since PHP 4.0.2 + * @link http://pear.php.net/manual/en/core.pear.php#core.pear.pear + */ +class PEAR +{ + // {{{ properties + + /** + * Whether to enable internal debug messages. + * + * @var bool + * @access private + */ + var $_debug = false; + + /** + * Default error mode for this object. + * + * @var int + * @access private + */ + var $_default_error_mode = null; + + /** + * Default error options used for this object when error mode + * is PEAR_ERROR_TRIGGER. + * + * @var int + * @access private + */ + var $_default_error_options = null; + + /** + * Default error handler (callback) for this object, if error mode is + * PEAR_ERROR_CALLBACK. + * + * @var string + * @access private + */ + var $_default_error_handler = ''; + + /** + * Which class to use for error objects. + * + * @var string + * @access private + */ + var $_error_class = 'PEAR_Error'; + + /** + * An array of expected errors. + * + * @var array + * @access private + */ + var $_expected_errors = array(); + + // }}} + + // {{{ constructor + + /** + * Constructor. Registers this object in + * $_PEAR_destructor_object_list for destructor emulation if a + * destructor object exists. + * + * @param string $error_class (optional) which class to use for + * error objects, defaults to PEAR_Error. + * @access public + * @return void + */ + function PEAR($error_class = null) + { + $classname = strtolower(get_class($this)); + if ($this->_debug) { + print "PEAR constructor called, class=$classname\n"; + } + if ($error_class !== null) { + $this->_error_class = $error_class; + } + while ($classname && strcasecmp($classname, "pear")) { + $destructor = "_$classname"; + if (method_exists($this, $destructor)) { + global $_PEAR_destructor_object_list; + $_PEAR_destructor_object_list[] = &$this; + if (!isset($GLOBALS['_PEAR_SHUTDOWN_REGISTERED'])) { + register_shutdown_function("_PEAR_call_destructors"); + $GLOBALS['_PEAR_SHUTDOWN_REGISTERED'] = true; + } + break; + } else { + $classname = get_parent_class($classname); + } + } + } + + // }}} + // {{{ destructor + + /** + * Destructor (the emulated type of...). Does nothing right now, + * but is included for forward compatibility, so subclass + * destructors should always call it. + * + * See the note in the class desciption about output from + * destructors. + * + * @access public + * @return void + */ + function _PEAR() { + if ($this->_debug) { + printf("PEAR destructor called, class=%s\n", strtolower(get_class($this))); + } + } + + // }}} + // {{{ getStaticProperty() + + /** + * If you have a class that's mostly/entirely static, and you need static + * properties, you can use this method to simulate them. Eg. in your method(s) + * do this: $myVar = &PEAR::getStaticProperty('myclass', 'myVar'); + * You MUST use a reference, or they will not persist! + * + * @access public + * @param string $class The calling classname, to prevent clashes + * @param string $var The variable to retrieve. + * @return mixed A reference to the variable. If not set it will be + * auto initialised to NULL. + */ + function &getStaticProperty($class, $var) + { + static $properties; + if (!isset($properties[$class])) { + $properties[$class] = array(); + } + if (!array_key_exists($var, $properties[$class])) { + $properties[$class][$var] = null; + } + return $properties[$class][$var]; + } + + // }}} + // {{{ registerShutdownFunc() + + /** + * Use this function to register a shutdown method for static + * classes. + * + * @access public + * @param mixed $func The function name (or array of class/method) to call + * @param mixed $args The arguments to pass to the function + * @return void + */ + function registerShutdownFunc($func, $args = array()) + { + // if we are called statically, there is a potential + // that no shutdown func is registered. Bug #6445 + if (!isset($GLOBALS['_PEAR_SHUTDOWN_REGISTERED'])) { + register_shutdown_function("_PEAR_call_destructors"); + $GLOBALS['_PEAR_SHUTDOWN_REGISTERED'] = true; + } + $GLOBALS['_PEAR_shutdown_funcs'][] = array($func, $args); + } + + // }}} + // {{{ isError() + + /** + * Tell whether a value is a PEAR error. + * + * @param mixed $data the value to test + * @param int $code if $data is an error object, return true + * only if $code is a string and + * $obj->getMessage() == $code or + * $code is an integer and $obj->getCode() == $code + * @access public + * @return bool true if parameter is an error + */ + function isError($data, $code = null) + { + if (is_a($data, 'PEAR_Error')) { + if (is_null($code)) { + return true; + } elseif (is_string($code)) { + return $data->getMessage() == $code; + } else { + return $data->getCode() == $code; + } + } + return false; + } + + // }}} + // {{{ setErrorHandling() + + /** + * Sets how errors generated by this object should be handled. + * Can be invoked both in objects and statically. If called + * statically, setErrorHandling sets the default behaviour for all + * PEAR objects. If called in an object, setErrorHandling sets + * the default behaviour for that object. + * + * @param int $mode + * One of PEAR_ERROR_RETURN, PEAR_ERROR_PRINT, + * PEAR_ERROR_TRIGGER, PEAR_ERROR_DIE, + * PEAR_ERROR_CALLBACK or PEAR_ERROR_EXCEPTION. + * + * @param mixed $options + * When $mode is PEAR_ERROR_TRIGGER, this is the error level (one + * of E_USER_NOTICE, E_USER_WARNING or E_USER_ERROR). + * + * When $mode is PEAR_ERROR_CALLBACK, this parameter is expected + * to be the callback function or method. A callback + * function is a string with the name of the function, a + * callback method is an array of two elements: the element + * at index 0 is the object, and the element at index 1 is + * the name of the method to call in the object. + * + * When $mode is PEAR_ERROR_PRINT or PEAR_ERROR_DIE, this is + * a printf format string used when printing the error + * message. + * + * @access public + * @return void + * @see PEAR_ERROR_RETURN + * @see PEAR_ERROR_PRINT + * @see PEAR_ERROR_TRIGGER + * @see PEAR_ERROR_DIE + * @see PEAR_ERROR_CALLBACK + * @see PEAR_ERROR_EXCEPTION + * + * @since PHP 4.0.5 + */ + + function setErrorHandling($mode = null, $options = null) + { + if (isset($this) && is_a($this, 'PEAR')) { + $setmode = &$this->_default_error_mode; + $setoptions = &$this->_default_error_options; + } else { + $setmode = &$GLOBALS['_PEAR_default_error_mode']; + $setoptions = &$GLOBALS['_PEAR_default_error_options']; + } + + switch ($mode) { + case PEAR_ERROR_EXCEPTION: + case PEAR_ERROR_RETURN: + case PEAR_ERROR_PRINT: + case PEAR_ERROR_TRIGGER: + case PEAR_ERROR_DIE: + case null: + $setmode = $mode; + $setoptions = $options; + break; + + case PEAR_ERROR_CALLBACK: + $setmode = $mode; + // class/object method callback + if (is_callable($options)) { + $setoptions = $options; + } else { + trigger_error("invalid error callback", E_USER_WARNING); + } + break; + + default: + trigger_error("invalid error mode", E_USER_WARNING); + break; + } + } + + // }}} + // {{{ expectError() + + /** + * This method is used to tell which errors you expect to get. + * Expected errors are always returned with error mode + * PEAR_ERROR_RETURN. Expected error codes are stored in a stack, + * and this method pushes a new element onto it. The list of + * expected errors are in effect until they are popped off the + * stack with the popExpect() method. + * + * Note that this method can not be called statically + * + * @param mixed $code a single error code or an array of error codes to expect + * + * @return int the new depth of the "expected errors" stack + * @access public + */ + function expectError($code = '*') + { + if (is_array($code)) { + array_push($this->_expected_errors, $code); + } else { + array_push($this->_expected_errors, array($code)); + } + return sizeof($this->_expected_errors); + } + + // }}} + // {{{ popExpect() + + /** + * This method pops one element off the expected error codes + * stack. + * + * @return array the list of error codes that were popped + */ + function popExpect() + { + return array_pop($this->_expected_errors); + } + + // }}} + // {{{ _checkDelExpect() + + /** + * This method checks unsets an error code if available + * + * @param mixed error code + * @return bool true if the error code was unset, false otherwise + * @access private + * @since PHP 4.3.0 + */ + function _checkDelExpect($error_code) + { + $deleted = false; + + foreach ($this->_expected_errors AS $key => $error_array) { + if (in_array($error_code, $error_array)) { + unset($this->_expected_errors[$key][array_search($error_code, $error_array)]); + $deleted = true; + } + + // clean up empty arrays + if (0 == count($this->_expected_errors[$key])) { + unset($this->_expected_errors[$key]); + } + } + return $deleted; + } + + // }}} + // {{{ delExpect() + + /** + * This method deletes all occurences of the specified element from + * the expected error codes stack. + * + * @param mixed $error_code error code that should be deleted + * @return mixed list of error codes that were deleted or error + * @access public + * @since PHP 4.3.0 + */ + function delExpect($error_code) + { + $deleted = false; + + if ((is_array($error_code) && (0 != count($error_code)))) { + // $error_code is a non-empty array here; + // we walk through it trying to unset all + // values + foreach($error_code as $key => $error) { + if ($this->_checkDelExpect($error)) { + $deleted = true; + } else { + $deleted = false; + } + } + return $deleted ? true : PEAR::raiseError("The expected error you submitted does not exist"); // IMPROVE ME + } elseif (!empty($error_code)) { + // $error_code comes alone, trying to unset it + if ($this->_checkDelExpect($error_code)) { + return true; + } else { + return PEAR::raiseError("The expected error you submitted does not exist"); // IMPROVE ME + } + } else { + // $error_code is empty + return PEAR::raiseError("The expected error you submitted is empty"); // IMPROVE ME + } + } + + // }}} + // {{{ raiseError() + + /** + * This method is a wrapper that returns an instance of the + * configured error class with this object's default error + * handling applied. If the $mode and $options parameters are not + * specified, the object's defaults are used. + * + * @param mixed $message a text error message or a PEAR error object + * + * @param int $code a numeric error code (it is up to your class + * to define these if you want to use codes) + * + * @param int $mode One of PEAR_ERROR_RETURN, PEAR_ERROR_PRINT, + * PEAR_ERROR_TRIGGER, PEAR_ERROR_DIE, + * PEAR_ERROR_CALLBACK, PEAR_ERROR_EXCEPTION. + * + * @param mixed $options If $mode is PEAR_ERROR_TRIGGER, this parameter + * specifies the PHP-internal error level (one of + * E_USER_NOTICE, E_USER_WARNING or E_USER_ERROR). + * If $mode is PEAR_ERROR_CALLBACK, this + * parameter specifies the callback function or + * method. In other error modes this parameter + * is ignored. + * + * @param string $userinfo If you need to pass along for example debug + * information, this parameter is meant for that. + * + * @param string $error_class The returned error object will be + * instantiated from this class, if specified. + * + * @param bool $skipmsg If true, raiseError will only pass error codes, + * the error message parameter will be dropped. + * + * @access public + * @return object a PEAR error object + * @see PEAR::setErrorHandling + * @since PHP 4.0.5 + */ + function &raiseError($message = null, + $code = null, + $mode = null, + $options = null, + $userinfo = null, + $error_class = null, + $skipmsg = false) + { + // The error is yet a PEAR error object + if (is_object($message)) { + $code = $message->getCode(); + $userinfo = $message->getUserInfo(); + $error_class = $message->getType(); + $message->error_message_prefix = ''; + $message = $message->getMessage(); + } + + if (isset($this) && isset($this->_expected_errors) && sizeof($this->_expected_errors) > 0 && sizeof($exp = end($this->_expected_errors))) { + if ($exp[0] == "*" || + (is_int(reset($exp)) && in_array($code, $exp)) || + (is_string(reset($exp)) && in_array($message, $exp))) { + $mode = PEAR_ERROR_RETURN; + } + } + // No mode given, try global ones + if ($mode === null) { + // Class error handler + if (isset($this) && isset($this->_default_error_mode)) { + $mode = $this->_default_error_mode; + $options = $this->_default_error_options; + // Global error handler + } elseif (isset($GLOBALS['_PEAR_default_error_mode'])) { + $mode = $GLOBALS['_PEAR_default_error_mode']; + $options = $GLOBALS['_PEAR_default_error_options']; + } + } + + if ($error_class !== null) { + $ec = $error_class; + } elseif (isset($this) && isset($this->_error_class)) { + $ec = $this->_error_class; + } else { + $ec = 'PEAR_Error'; + } + if (intval(PHP_VERSION) < 5) { + // little non-eval hack to fix bug #12147 + include 'PEAR/FixPHP5PEARWarnings.php'; + return $a; + } + if ($skipmsg) { + $a = new $ec($code, $mode, $options, $userinfo); + } else { + $a = new $ec($message, $code, $mode, $options, $userinfo); + } + return $a; + } + + // }}} + // {{{ throwError() + + /** + * Simpler form of raiseError with fewer options. In most cases + * message, code and userinfo are enough. + * + * @param string $message + * + */ + function &throwError($message = null, + $code = null, + $userinfo = null) + { + if (isset($this) && is_a($this, 'PEAR')) { + $a = &$this->raiseError($message, $code, null, null, $userinfo); + return $a; + } else { + $a = &PEAR::raiseError($message, $code, null, null, $userinfo); + return $a; + } + } + + // }}} + function staticPushErrorHandling($mode, $options = null) + { + $stack = &$GLOBALS['_PEAR_error_handler_stack']; + $def_mode = &$GLOBALS['_PEAR_default_error_mode']; + $def_options = &$GLOBALS['_PEAR_default_error_options']; + $stack[] = array($def_mode, $def_options); + switch ($mode) { + case PEAR_ERROR_EXCEPTION: + case PEAR_ERROR_RETURN: + case PEAR_ERROR_PRINT: + case PEAR_ERROR_TRIGGER: + case PEAR_ERROR_DIE: + case null: + $def_mode = $mode; + $def_options = $options; + break; + + case PEAR_ERROR_CALLBACK: + $def_mode = $mode; + // class/object method callback + if (is_callable($options)) { + $def_options = $options; + } else { + trigger_error("invalid error callback", E_USER_WARNING); + } + break; + + default: + trigger_error("invalid error mode", E_USER_WARNING); + break; + } + $stack[] = array($mode, $options); + return true; + } + + function staticPopErrorHandling() + { + $stack = &$GLOBALS['_PEAR_error_handler_stack']; + $setmode = &$GLOBALS['_PEAR_default_error_mode']; + $setoptions = &$GLOBALS['_PEAR_default_error_options']; + array_pop($stack); + list($mode, $options) = $stack[sizeof($stack) - 1]; + array_pop($stack); + switch ($mode) { + case PEAR_ERROR_EXCEPTION: + case PEAR_ERROR_RETURN: + case PEAR_ERROR_PRINT: + case PEAR_ERROR_TRIGGER: + case PEAR_ERROR_DIE: + case null: + $setmode = $mode; + $setoptions = $options; + break; + + case PEAR_ERROR_CALLBACK: + $setmode = $mode; + // class/object method callback + if (is_callable($options)) { + $setoptions = $options; + } else { + trigger_error("invalid error callback", E_USER_WARNING); + } + break; + + default: + trigger_error("invalid error mode", E_USER_WARNING); + break; + } + return true; + } + + // {{{ pushErrorHandling() + + /** + * Push a new error handler on top of the error handler options stack. With this + * you can easily override the actual error handler for some code and restore + * it later with popErrorHandling. + * + * @param mixed $mode (same as setErrorHandling) + * @param mixed $options (same as setErrorHandling) + * + * @return bool Always true + * + * @see PEAR::setErrorHandling + */ + function pushErrorHandling($mode, $options = null) + { + $stack = &$GLOBALS['_PEAR_error_handler_stack']; + if (isset($this) && is_a($this, 'PEAR')) { + $def_mode = &$this->_default_error_mode; + $def_options = &$this->_default_error_options; + } else { + $def_mode = &$GLOBALS['_PEAR_default_error_mode']; + $def_options = &$GLOBALS['_PEAR_default_error_options']; + } + $stack[] = array($def_mode, $def_options); + + if (isset($this) && is_a($this, 'PEAR')) { + $this->setErrorHandling($mode, $options); + } else { + PEAR::setErrorHandling($mode, $options); + } + $stack[] = array($mode, $options); + return true; + } + + // }}} + // {{{ popErrorHandling() + + /** + * Pop the last error handler used + * + * @return bool Always true + * + * @see PEAR::pushErrorHandling + */ + function popErrorHandling() + { + $stack = &$GLOBALS['_PEAR_error_handler_stack']; + array_pop($stack); + list($mode, $options) = $stack[sizeof($stack) - 1]; + array_pop($stack); + if (isset($this) && is_a($this, 'PEAR')) { + $this->setErrorHandling($mode, $options); + } else { + PEAR::setErrorHandling($mode, $options); + } + return true; + } + + // }}} + // {{{ loadExtension() + + /** + * OS independant PHP extension load. Remember to take care + * on the correct extension name for case sensitive OSes. + * + * @param string $ext The extension name + * @return bool Success or not on the dl() call + */ + function loadExtension($ext) + { + if (!extension_loaded($ext)) { + // if either returns true dl() will produce a FATAL error, stop that + if ((ini_get('enable_dl') != 1) || (ini_get('safe_mode') == 1)) { + return false; + } + if (OS_WINDOWS) { + $suffix = '.dll'; + } elseif (PHP_OS == 'HP-UX') { + $suffix = '.sl'; + } elseif (PHP_OS == 'AIX') { + $suffix = '.a'; + } elseif (PHP_OS == 'OSX') { + $suffix = '.bundle'; + } else { + $suffix = '.so'; + } + return @dl('php_'.$ext.$suffix) || @dl($ext.$suffix); + } + return true; + } + + // }}} +} + +// {{{ _PEAR_call_destructors() + +function _PEAR_call_destructors() +{ + global $_PEAR_destructor_object_list; + if (is_array($_PEAR_destructor_object_list) && + sizeof($_PEAR_destructor_object_list)) + { + reset($_PEAR_destructor_object_list); + if (PEAR::getStaticProperty('PEAR', 'destructlifo')) { + $_PEAR_destructor_object_list = array_reverse($_PEAR_destructor_object_list); + } + while (list($k, $objref) = each($_PEAR_destructor_object_list)) { + $classname = get_class($objref); + while ($classname) { + $destructor = "_$classname"; + if (method_exists($objref, $destructor)) { + $objref->$destructor(); + break; + } else { + $classname = get_parent_class($classname); + } + } + } + // Empty the object list to ensure that destructors are + // not called more than once. + $_PEAR_destructor_object_list = array(); + } + + // Now call the shutdown functions + if (is_array($GLOBALS['_PEAR_shutdown_funcs']) AND !empty($GLOBALS['_PEAR_shutdown_funcs'])) { + foreach ($GLOBALS['_PEAR_shutdown_funcs'] as $value) { + call_user_func_array($value[0], $value[1]); + } + } +} + +// }}} +/** + * Standard PEAR error class for PHP 4 + * + * This class is supserseded by {@link PEAR_Exception} in PHP 5 + * + * @category pear + * @package PEAR + * @author Stig Bakken + * @author Tomas V.V. Cox + * @author Gregory Beaver + * @copyright 1997-2006 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version Release: 1.7.2 + * @link http://pear.php.net/manual/en/core.pear.pear-error.php + * @see PEAR::raiseError(), PEAR::throwError() + * @since Class available since PHP 4.0.2 + */ +class PEAR_Error +{ + // {{{ properties + + var $error_message_prefix = ''; + var $mode = PEAR_ERROR_RETURN; + var $level = E_USER_NOTICE; + var $code = -1; + var $message = ''; + var $userinfo = ''; + var $backtrace = null; + + // }}} + // {{{ constructor + + /** + * PEAR_Error constructor + * + * @param string $message message + * + * @param int $code (optional) error code + * + * @param int $mode (optional) error mode, one of: PEAR_ERROR_RETURN, + * PEAR_ERROR_PRINT, PEAR_ERROR_DIE, PEAR_ERROR_TRIGGER, + * PEAR_ERROR_CALLBACK or PEAR_ERROR_EXCEPTION + * + * @param mixed $options (optional) error level, _OR_ in the case of + * PEAR_ERROR_CALLBACK, the callback function or object/method + * tuple. + * + * @param string $userinfo (optional) additional user/debug info + * + * @access public + * + */ + function PEAR_Error($message = 'unknown error', $code = null, + $mode = null, $options = null, $userinfo = null) + { + if ($mode === null) { + $mode = PEAR_ERROR_RETURN; + } + $this->message = $message; + $this->code = $code; + $this->mode = $mode; + $this->userinfo = $userinfo; + if (!PEAR::getStaticProperty('PEAR_Error', 'skiptrace')) { + $this->backtrace = debug_backtrace(); + if (isset($this->backtrace[0]) && isset($this->backtrace[0]['object'])) { + unset($this->backtrace[0]['object']); + } + } + if ($mode & PEAR_ERROR_CALLBACK) { + $this->level = E_USER_NOTICE; + $this->callback = $options; + } else { + if ($options === null) { + $options = E_USER_NOTICE; + } + $this->level = $options; + $this->callback = null; + } + if ($this->mode & PEAR_ERROR_PRINT) { + if (is_null($options) || is_int($options)) { + $format = "%s"; + } else { + $format = $options; + } + printf($format, $this->getMessage()); + } + if ($this->mode & PEAR_ERROR_TRIGGER) { + trigger_error($this->getMessage(), $this->level); + } + if ($this->mode & PEAR_ERROR_DIE) { + $msg = $this->getMessage(); + if (is_null($options) || is_int($options)) { + $format = "%s"; + if (substr($msg, -1) != "\n") { + $msg .= "\n"; + } + } else { + $format = $options; + } + die(sprintf($format, $msg)); + } + if ($this->mode & PEAR_ERROR_CALLBACK) { + if (is_callable($this->callback)) { + call_user_func($this->callback, $this); + } + } + if ($this->mode & PEAR_ERROR_EXCEPTION) { + trigger_error("PEAR_ERROR_EXCEPTION is obsolete, use class PEAR_Exception for exceptions", E_USER_WARNING); + eval('$e = new Exception($this->message, $this->code);throw($e);'); + } + } + + // }}} + // {{{ getMode() + + /** + * Get the error mode from an error object. + * + * @return int error mode + * @access public + */ + function getMode() { + return $this->mode; + } + + // }}} + // {{{ getCallback() + + /** + * Get the callback function/method from an error object. + * + * @return mixed callback function or object/method array + * @access public + */ + function getCallback() { + return $this->callback; + } + + // }}} + // {{{ getMessage() + + + /** + * Get the error message from an error object. + * + * @return string full error message + * @access public + */ + function getMessage() + { + return ($this->error_message_prefix . $this->message); + } + + + // }}} + // {{{ getCode() + + /** + * Get error code from an error object + * + * @return int error code + * @access public + */ + function getCode() + { + return $this->code; + } + + // }}} + // {{{ getType() + + /** + * Get the name of this error/exception. + * + * @return string error/exception name (type) + * @access public + */ + function getType() + { + return get_class($this); + } + + // }}} + // {{{ getUserInfo() + + /** + * Get additional user-supplied information. + * + * @return string user-supplied information + * @access public + */ + function getUserInfo() + { + return $this->userinfo; + } + + // }}} + // {{{ getDebugInfo() + + /** + * Get additional debug information supplied by the application. + * + * @return string debug information + * @access public + */ + function getDebugInfo() + { + return $this->getUserInfo(); + } + + // }}} + // {{{ getBacktrace() + + /** + * Get the call backtrace from where the error was generated. + * Supported with PHP 4.3.0 or newer. + * + * @param int $frame (optional) what frame to fetch + * @return array Backtrace, or NULL if not available. + * @access public + */ + function getBacktrace($frame = null) + { + if (defined('PEAR_IGNORE_BACKTRACE')) { + return null; + } + if ($frame === null) { + return $this->backtrace; + } + return $this->backtrace[$frame]; + } + + // }}} + // {{{ addUserInfo() + + function addUserInfo($info) + { + if (empty($this->userinfo)) { + $this->userinfo = $info; + } else { + $this->userinfo .= " ** $info"; + } + } + + // }}} + // {{{ toString() + function __toString() + { + return $this->getMessage(); + } + // }}} + // {{{ toString() + + /** + * Make a string representation of this object. + * + * @return string a string with an object summary + * @access public + */ + function toString() { + $modes = array(); + $levels = array(E_USER_NOTICE => 'notice', + E_USER_WARNING => 'warning', + E_USER_ERROR => 'error'); + if ($this->mode & PEAR_ERROR_CALLBACK) { + if (is_array($this->callback)) { + $callback = (is_object($this->callback[0]) ? + strtolower(get_class($this->callback[0])) : + $this->callback[0]) . '::' . + $this->callback[1]; + } else { + $callback = $this->callback; + } + return sprintf('[%s: message="%s" code=%d mode=callback '. + 'callback=%s prefix="%s" info="%s"]', + strtolower(get_class($this)), $this->message, $this->code, + $callback, $this->error_message_prefix, + $this->userinfo); + } + if ($this->mode & PEAR_ERROR_PRINT) { + $modes[] = 'print'; + } + if ($this->mode & PEAR_ERROR_TRIGGER) { + $modes[] = 'trigger'; + } + if ($this->mode & PEAR_ERROR_DIE) { + $modes[] = 'die'; + } + if ($this->mode & PEAR_ERROR_RETURN) { + $modes[] = 'return'; + } + return sprintf('[%s: message="%s" code=%d mode=%s level=%s '. + 'prefix="%s" info="%s"]', + strtolower(get_class($this)), $this->message, $this->code, + implode("|", $modes), $levels[$this->level], + $this->error_message_prefix, + $this->userinfo); + } + + // }}} +} + +/* + * Local Variables: + * mode: php + * tab-width: 4 + * c-basic-offset: 4 + * End: + */ +?> diff --git a/oss/vtiger/trunk/vtlib/thirdparty/network/Request.php b/oss/vtiger/trunk/vtlib/thirdparty/network/Request.php new file mode 100644 index 00000000..291fa8d1 --- /dev/null +++ b/oss/vtiger/trunk/vtlib/thirdparty/network/Request.php @@ -0,0 +1,1522 @@ + + * @author Alexey Borzov + * @copyright 2002-2007 Richard Heyes + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: Request.php,v 1.63 2008/10/11 11:07:10 avb Exp $ + * @link http://pear.php.net/package/HTTP_Request/ + */ + +/** + * PEAR and PEAR_Error classes (for error handling) + */ +require_once dirname(__FILE__) . '/PEAR.php'; + +/** + * Socket class + */ +require_once dirname(__FILE__) . '/Net/Socket.php'; +/** + * URL handling class + */ +require_once dirname(__FILE__) . '/Net/URL.php'; + +/**#@+ + * Constants for HTTP request methods + */ +define('HTTP_REQUEST_METHOD_GET', 'GET', true); +define('HTTP_REQUEST_METHOD_HEAD', 'HEAD', true); +define('HTTP_REQUEST_METHOD_POST', 'POST', true); +define('HTTP_REQUEST_METHOD_PUT', 'PUT', true); +define('HTTP_REQUEST_METHOD_DELETE', 'DELETE', true); +define('HTTP_REQUEST_METHOD_OPTIONS', 'OPTIONS', true); +define('HTTP_REQUEST_METHOD_TRACE', 'TRACE', true); +/**#@-*/ + +/**#@+ + * Constants for HTTP request error codes + */ +define('HTTP_REQUEST_ERROR_FILE', 1); +define('HTTP_REQUEST_ERROR_URL', 2); +define('HTTP_REQUEST_ERROR_PROXY', 4); +define('HTTP_REQUEST_ERROR_REDIRECTS', 8); +define('HTTP_REQUEST_ERROR_RESPONSE', 16); +define('HTTP_REQUEST_ERROR_GZIP_METHOD', 32); +define('HTTP_REQUEST_ERROR_GZIP_READ', 64); +define('HTTP_REQUEST_ERROR_GZIP_DATA', 128); +define('HTTP_REQUEST_ERROR_GZIP_CRC', 256); +/**#@-*/ + +/**#@+ + * Constants for HTTP protocol versions + */ +define('HTTP_REQUEST_HTTP_VER_1_0', '1.0', true); +define('HTTP_REQUEST_HTTP_VER_1_1', '1.1', true); +/**#@-*/ + +if (extension_loaded('mbstring') && (2 & ini_get('mbstring.func_overload'))) { + /** + * Whether string functions are overloaded by their mbstring equivalents + */ + define('HTTP_REQUEST_MBSTRING', true); +} else { + /** + * @ignore + */ + define('HTTP_REQUEST_MBSTRING', false); +} + +/** + * Class for performing HTTP requests + * + * Simple example (fetches yahoo.com and displays it): + * + * $a = &new HTTP_Request('http://www.yahoo.com/'); + * $a->sendRequest(); + * echo $a->getResponseBody(); + * + * + * @category HTTP + * @package HTTP_Request + * @author Richard Heyes + * @author Alexey Borzov + * @version Release: 1.4.4 + */ +class HTTP_Request +{ + /**#@+ + * @access private + */ + /** + * Instance of Net_URL + * @var Net_URL + */ + var $_url; + + /** + * Type of request + * @var string + */ + var $_method; + + /** + * HTTP Version + * @var string + */ + var $_http; + + /** + * Request headers + * @var array + */ + var $_requestHeaders; + + /** + * Basic Auth Username + * @var string + */ + var $_user; + + /** + * Basic Auth Password + * @var string + */ + var $_pass; + + /** + * Socket object + * @var Net_Socket + */ + var $_sock; + + /** + * Proxy server + * @var string + */ + var $_proxy_host; + + /** + * Proxy port + * @var integer + */ + var $_proxy_port; + + /** + * Proxy username + * @var string + */ + var $_proxy_user; + + /** + * Proxy password + * @var string + */ + var $_proxy_pass; + + /** + * Post data + * @var array + */ + var $_postData; + + /** + * Request body + * @var string + */ + var $_body; + + /** + * A list of methods that MUST NOT have a request body, per RFC 2616 + * @var array + */ + var $_bodyDisallowed = array('TRACE'); + + /** + * Methods having defined semantics for request body + * + * Content-Length header (indicating that the body follows, section 4.3 of + * RFC 2616) will be sent for these methods even if no body was added + * + * @var array + */ + var $_bodyRequired = array('POST', 'PUT'); + + /** + * Files to post + * @var array + */ + var $_postFiles = array(); + + /** + * Connection timeout. + * @var float + */ + var $_timeout; + + /** + * HTTP_Response object + * @var HTTP_Response + */ + var $_response; + + /** + * Whether to allow redirects + * @var boolean + */ + var $_allowRedirects; + + /** + * Maximum redirects allowed + * @var integer + */ + var $_maxRedirects; + + /** + * Current number of redirects + * @var integer + */ + var $_redirects; + + /** + * Whether to append brackets [] to array variables + * @var bool + */ + var $_useBrackets = true; + + /** + * Attached listeners + * @var array + */ + var $_listeners = array(); + + /** + * Whether to save response body in response object property + * @var bool + */ + var $_saveBody = true; + + /** + * Timeout for reading from socket (array(seconds, microseconds)) + * @var array + */ + var $_readTimeout = null; + + /** + * Options to pass to Net_Socket::connect. See stream_context_create + * @var array + */ + var $_socketOptions = null; + /**#@-*/ + + /** + * Constructor + * + * Sets up the object + * @param string The url to fetch/access + * @param array Associative array of parameters which can have the following keys: + *
    + *
  • method - Method to use, GET, POST etc (string)
  • + *
  • http - HTTP Version to use, 1.0 or 1.1 (string)
  • + *
  • user - Basic Auth username (string)
  • + *
  • pass - Basic Auth password (string)
  • + *
  • proxy_host - Proxy server host (string)
  • + *
  • proxy_port - Proxy server port (integer)
  • + *
  • proxy_user - Proxy auth username (string)
  • + *
  • proxy_pass - Proxy auth password (string)
  • + *
  • timeout - Connection timeout in seconds (float)
  • + *
  • allowRedirects - Whether to follow redirects or not (bool)
  • + *
  • maxRedirects - Max number of redirects to follow (integer)
  • + *
  • useBrackets - Whether to append [] to array variable names (bool)
  • + *
  • saveBody - Whether to save response body in response object property (bool)
  • + *
  • readTimeout - Timeout for reading / writing data over the socket (array (seconds, microseconds))
  • + *
  • socketOptions - Options to pass to Net_Socket object (array)
  • + *
+ * @access public + */ + function HTTP_Request($url = '', $params = array()) + { + $this->_method = HTTP_REQUEST_METHOD_GET; + $this->_http = HTTP_REQUEST_HTTP_VER_1_1; + $this->_requestHeaders = array(); + $this->_postData = array(); + $this->_body = null; + + $this->_user = null; + $this->_pass = null; + + $this->_proxy_host = null; + $this->_proxy_port = null; + $this->_proxy_user = null; + $this->_proxy_pass = null; + + $this->_allowRedirects = false; + $this->_maxRedirects = 3; + $this->_redirects = 0; + + $this->_timeout = null; + $this->_response = null; + + foreach ($params as $key => $value) { + $this->{'_' . $key} = $value; + } + + if (!empty($url)) { + $this->setURL($url); + } + + // Default useragent + $this->addHeader('User-Agent', 'PEAR HTTP_Request class ( http://pear.php.net/ )'); + + // We don't do keep-alives by default + $this->addHeader('Connection', 'close'); + + // Basic authentication + if (!empty($this->_user)) { + $this->addHeader('Authorization', 'Basic ' . base64_encode($this->_user . ':' . $this->_pass)); + } + + // Proxy authentication (see bug #5913) + if (!empty($this->_proxy_user)) { + $this->addHeader('Proxy-Authorization', 'Basic ' . base64_encode($this->_proxy_user . ':' . $this->_proxy_pass)); + } + + // Use gzip encoding if possible + if (HTTP_REQUEST_HTTP_VER_1_1 == $this->_http && extension_loaded('zlib')) { + $this->addHeader('Accept-Encoding', 'gzip'); + } + } + + /** + * Generates a Host header for HTTP/1.1 requests + * + * @access private + * @return string + */ + function _generateHostHeader() + { + if ($this->_url->port != 80 AND strcasecmp($this->_url->protocol, 'http') == 0) { + $host = $this->_url->host . ':' . $this->_url->port; + + } elseif ($this->_url->port != 443 AND strcasecmp($this->_url->protocol, 'https') == 0) { + $host = $this->_url->host . ':' . $this->_url->port; + + } elseif ($this->_url->port == 443 AND strcasecmp($this->_url->protocol, 'https') == 0 AND strpos($this->_url->url, ':443') !== false) { + $host = $this->_url->host . ':' . $this->_url->port; + + } else { + $host = $this->_url->host; + } + + return $host; + } + + /** + * Resets the object to its initial state (DEPRECATED). + * Takes the same parameters as the constructor. + * + * @param string $url The url to be requested + * @param array $params Associative array of parameters + * (see constructor for details) + * @access public + * @deprecated deprecated since 1.2, call the constructor if this is necessary + */ + function reset($url, $params = array()) + { + $this->HTTP_Request($url, $params); + } + + /** + * Sets the URL to be requested + * + * @param string The url to be requested + * @access public + */ + function setURL($url) + { + $this->_url = &new Net_URL($url, $this->_useBrackets); + + if (!empty($this->_url->user) || !empty($this->_url->pass)) { + $this->setBasicAuth($this->_url->user, $this->_url->pass); + } + + if (HTTP_REQUEST_HTTP_VER_1_1 == $this->_http) { + $this->addHeader('Host', $this->_generateHostHeader()); + } + + // set '/' instead of empty path rather than check later (see bug #8662) + if (empty($this->_url->path)) { + $this->_url->path = '/'; + } + } + + /** + * Returns the current request URL + * + * @return string Current request URL + * @access public + */ + function getUrl() + { + return empty($this->_url)? '': $this->_url->getUrl(); + } + + /** + * Sets a proxy to be used + * + * @param string Proxy host + * @param int Proxy port + * @param string Proxy username + * @param string Proxy password + * @access public + */ + function setProxy($host, $port = 8080, $user = null, $pass = null) + { + $this->_proxy_host = $host; + $this->_proxy_port = $port; + $this->_proxy_user = $user; + $this->_proxy_pass = $pass; + + if (!empty($user)) { + $this->addHeader('Proxy-Authorization', 'Basic ' . base64_encode($user . ':' . $pass)); + } + } + + /** + * Sets basic authentication parameters + * + * @param string Username + * @param string Password + */ + function setBasicAuth($user, $pass) + { + $this->_user = $user; + $this->_pass = $pass; + + $this->addHeader('Authorization', 'Basic ' . base64_encode($user . ':' . $pass)); + } + + /** + * Sets the method to be used, GET, POST etc. + * + * @param string Method to use. Use the defined constants for this + * @access public + */ + function setMethod($method) + { + $this->_method = $method; + } + + /** + * Sets the HTTP version to use, 1.0 or 1.1 + * + * @param string Version to use. Use the defined constants for this + * @access public + */ + function setHttpVer($http) + { + $this->_http = $http; + } + + /** + * Adds a request header + * + * @param string Header name + * @param string Header value + * @access public + */ + function addHeader($name, $value) + { + $this->_requestHeaders[strtolower($name)] = $value; + } + + /** + * Removes a request header + * + * @param string Header name to remove + * @access public + */ + function removeHeader($name) + { + if (isset($this->_requestHeaders[strtolower($name)])) { + unset($this->_requestHeaders[strtolower($name)]); + } + } + + /** + * Adds a querystring parameter + * + * @param string Querystring parameter name + * @param string Querystring parameter value + * @param bool Whether the value is already urlencoded or not, default = not + * @access public + */ + function addQueryString($name, $value, $preencoded = false) + { + $this->_url->addQueryString($name, $value, $preencoded); + } + + /** + * Sets the querystring to literally what you supply + * + * @param string The querystring data. Should be of the format foo=bar&x=y etc + * @param bool Whether data is already urlencoded or not, default = already encoded + * @access public + */ + function addRawQueryString($querystring, $preencoded = true) + { + $this->_url->addRawQueryString($querystring, $preencoded); + } + + /** + * Adds postdata items + * + * @param string Post data name + * @param string Post data value + * @param bool Whether data is already urlencoded or not, default = not + * @access public + */ + function addPostData($name, $value, $preencoded = false) + { + if ($preencoded) { + $this->_postData[$name] = $value; + } else { + $this->_postData[$name] = $this->_arrayMapRecursive('urlencode', $value); + } + } + + /** + * Recursively applies the callback function to the value + * + * @param mixed Callback function + * @param mixed Value to process + * @access private + * @return mixed Processed value + */ + function _arrayMapRecursive($callback, $value) + { + if (!is_array($value)) { + return call_user_func($callback, $value); + } else { + $map = array(); + foreach ($value as $k => $v) { + $map[$k] = $this->_arrayMapRecursive($callback, $v); + } + return $map; + } + } + + /** + * Adds a file to form-based file upload + * + * Used to emulate file upload via a HTML form. The method also sets + * Content-Type of HTTP request to 'multipart/form-data'. + * + * If you just want to send the contents of a file as the body of HTTP + * request you should use setBody() method. + * + * @access public + * @param string name of file-upload field + * @param mixed file name(s) + * @param mixed content-type(s) of file(s) being uploaded + * @return bool true on success + * @throws PEAR_Error + */ + function addFile($inputName, $fileName, $contentType = 'application/octet-stream') + { + if (!is_array($fileName) && !is_readable($fileName)) { + return PEAR::raiseError("File '{$fileName}' is not readable", HTTP_REQUEST_ERROR_FILE); + } elseif (is_array($fileName)) { + foreach ($fileName as $name) { + if (!is_readable($name)) { + return PEAR::raiseError("File '{$name}' is not readable", HTTP_REQUEST_ERROR_FILE); + } + } + } + $this->addHeader('Content-Type', 'multipart/form-data'); + $this->_postFiles[$inputName] = array( + 'name' => $fileName, + 'type' => $contentType + ); + return true; + } + + /** + * Adds raw postdata (DEPRECATED) + * + * @param string The data + * @param bool Whether data is preencoded or not, default = already encoded + * @access public + * @deprecated deprecated since 1.3.0, method setBody() should be used instead + */ + function addRawPostData($postdata, $preencoded = true) + { + $this->_body = $preencoded ? $postdata : urlencode($postdata); + } + + /** + * Sets the request body (for POST, PUT and similar requests) + * + * @param string Request body + * @access public + */ + function setBody($body) + { + $this->_body = $body; + } + + /** + * Clears any postdata that has been added (DEPRECATED). + * + * Useful for multiple request scenarios. + * + * @access public + * @deprecated deprecated since 1.2 + */ + function clearPostData() + { + $this->_postData = null; + } + + /** + * Appends a cookie to "Cookie:" header + * + * @param string $name cookie name + * @param string $value cookie value + * @access public + */ + function addCookie($name, $value) + { + $cookies = isset($this->_requestHeaders['cookie']) ? $this->_requestHeaders['cookie']. '; ' : ''; + $this->addHeader('Cookie', $cookies . $name . '=' . $value); + } + + /** + * Clears any cookies that have been added (DEPRECATED). + * + * Useful for multiple request scenarios + * + * @access public + * @deprecated deprecated since 1.2 + */ + function clearCookies() + { + $this->removeHeader('Cookie'); + } + + /** + * Sends the request + * + * @access public + * @param bool Whether to store response body in Response object property, + * set this to false if downloading a LARGE file and using a Listener + * @return mixed PEAR error on error, true otherwise + */ + function sendRequest($saveBody = true) + { + if (!is_a($this->_url, 'Net_URL')) { + return PEAR::raiseError('No URL given', HTTP_REQUEST_ERROR_URL); + } + + $host = isset($this->_proxy_host) ? $this->_proxy_host : $this->_url->host; + $port = isset($this->_proxy_port) ? $this->_proxy_port : $this->_url->port; + + if (strcasecmp($this->_url->protocol, 'https') == 0) { + // Bug #14127, don't try connecting to HTTPS sites without OpenSSL + if (version_compare(PHP_VERSION, '4.3.0', '<') || !extension_loaded('openssl')) { + return PEAR::raiseError('Need PHP 4.3.0 or later with OpenSSL support for https:// requests', + HTTP_REQUEST_ERROR_URL); + } elseif (isset($this->_proxy_host)) { + return PEAR::raiseError('HTTPS proxies are not supported', HTTP_REQUEST_ERROR_PROXY); + } + $host = 'ssl://' . $host; + } + + // magic quotes may fuck up file uploads and chunked response processing + $magicQuotes = ini_get('magic_quotes_runtime'); + ini_set('magic_quotes_runtime', false); + + // RFC 2068, section 19.7.1: A client MUST NOT send the Keep-Alive + // connection token to a proxy server... + if (isset($this->_proxy_host) && !empty($this->_requestHeaders['connection']) && + 'Keep-Alive' == $this->_requestHeaders['connection']) + { + $this->removeHeader('connection'); + } + + $keepAlive = (HTTP_REQUEST_HTTP_VER_1_1 == $this->_http && empty($this->_requestHeaders['connection'])) || + (!empty($this->_requestHeaders['connection']) && 'Keep-Alive' == $this->_requestHeaders['connection']); + $sockets = &PEAR::getStaticProperty('HTTP_Request', 'sockets'); + $sockKey = $host . ':' . $port; + unset($this->_sock); + + // There is a connected socket in the "static" property? + if ($keepAlive && !empty($sockets[$sockKey]) && + !empty($sockets[$sockKey]->fp)) + { + $this->_sock =& $sockets[$sockKey]; + $err = null; + } else { + $this->_notify('connect'); + $this->_sock =& new Net_Socket(); + $err = $this->_sock->connect($host, $port, null, $this->_timeout, $this->_socketOptions); + } + PEAR::isError($err) or $err = $this->_sock->write($this->_buildRequest()); + + if (!PEAR::isError($err)) { + if (!empty($this->_readTimeout)) { + $this->_sock->setTimeout($this->_readTimeout[0], $this->_readTimeout[1]); + } + + $this->_notify('sentRequest'); + + // Read the response + $this->_response = &new HTTP_Response($this->_sock, $this->_listeners); + $err = $this->_response->process( + $this->_saveBody && $saveBody, + HTTP_REQUEST_METHOD_HEAD != $this->_method + ); + + if ($keepAlive) { + $keepAlive = (isset($this->_response->_headers['content-length']) + || (isset($this->_response->_headers['transfer-encoding']) + && strtolower($this->_response->_headers['transfer-encoding']) == 'chunked')); + if ($keepAlive) { + if (isset($this->_response->_headers['connection'])) { + $keepAlive = strtolower($this->_response->_headers['connection']) == 'keep-alive'; + } else { + $keepAlive = 'HTTP/'.HTTP_REQUEST_HTTP_VER_1_1 == $this->_response->_protocol; + } + } + } + } + + ini_set('magic_quotes_runtime', $magicQuotes); + + if (PEAR::isError($err)) { + return $err; + } + + if (!$keepAlive) { + $this->disconnect(); + // Store the connected socket in "static" property + } elseif (empty($sockets[$sockKey]) || empty($sockets[$sockKey]->fp)) { + $sockets[$sockKey] =& $this->_sock; + } + + // Check for redirection + if ( $this->_allowRedirects + AND $this->_redirects <= $this->_maxRedirects + AND $this->getResponseCode() > 300 + AND $this->getResponseCode() < 399 + AND !empty($this->_response->_headers['location'])) { + + + $redirect = $this->_response->_headers['location']; + + // Absolute URL + if (preg_match('/^https?:\/\//i', $redirect)) { + $this->_url = &new Net_URL($redirect); + $this->addHeader('Host', $this->_generateHostHeader()); + // Absolute path + } elseif ($redirect{0} == '/') { + $this->_url->path = $redirect; + + // Relative path + } elseif (substr($redirect, 0, 3) == '../' OR substr($redirect, 0, 2) == './') { + if (substr($this->_url->path, -1) == '/') { + $redirect = $this->_url->path . $redirect; + } else { + $redirect = dirname($this->_url->path) . '/' . $redirect; + } + $redirect = Net_URL::resolvePath($redirect); + $this->_url->path = $redirect; + + // Filename, no path + } else { + if (substr($this->_url->path, -1) == '/') { + $redirect = $this->_url->path . $redirect; + } else { + $redirect = dirname($this->_url->path) . '/' . $redirect; + } + $this->_url->path = $redirect; + } + + $this->_redirects++; + return $this->sendRequest($saveBody); + + // Too many redirects + } elseif ($this->_allowRedirects AND $this->_redirects > $this->_maxRedirects) { + return PEAR::raiseError('Too many redirects', HTTP_REQUEST_ERROR_REDIRECTS); + } + + return true; + } + + /** + * Disconnect the socket, if connected. Only useful if using Keep-Alive. + * + * @access public + */ + function disconnect() + { + if (!empty($this->_sock) && !empty($this->_sock->fp)) { + $this->_notify('disconnect'); + $this->_sock->disconnect(); + } + } + + /** + * Returns the response code + * + * @access public + * @return mixed Response code, false if not set + */ + function getResponseCode() + { + return isset($this->_response->_code) ? $this->_response->_code : false; + } + + /** + * Returns the response reason phrase + * + * @access public + * @return mixed Response reason phrase, false if not set + */ + function getResponseReason() + { + return isset($this->_response->_reason) ? $this->_response->_reason : false; + } + + /** + * Returns either the named header or all if no name given + * + * @access public + * @param string The header name to return, do not set to get all headers + * @return mixed either the value of $headername (false if header is not present) + * or an array of all headers + */ + function getResponseHeader($headername = null) + { + if (!isset($headername)) { + return isset($this->_response->_headers)? $this->_response->_headers: array(); + } else { + $headername = strtolower($headername); + return isset($this->_response->_headers[$headername]) ? $this->_response->_headers[$headername] : false; + } + } + + /** + * Returns the body of the response + * + * @access public + * @return mixed response body, false if not set + */ + function getResponseBody() + { + return isset($this->_response->_body) ? $this->_response->_body : false; + } + + /** + * Returns cookies set in response + * + * @access public + * @return mixed array of response cookies, false if none are present + */ + function getResponseCookies() + { + return isset($this->_response->_cookies) ? $this->_response->_cookies : false; + } + + /** + * Builds the request string + * + * @access private + * @return string The request string + */ + function _buildRequest() + { + $separator = ini_get('arg_separator.output'); + ini_set('arg_separator.output', '&'); + $querystring = ($querystring = $this->_url->getQueryString()) ? '?' . $querystring : ''; + ini_set('arg_separator.output', $separator); + + $host = isset($this->_proxy_host) ? $this->_url->protocol . '://' . $this->_url->host : ''; + $port = (isset($this->_proxy_host) AND $this->_url->port != 80) ? ':' . $this->_url->port : ''; + $path = $this->_url->path . $querystring; + $url = $host . $port . $path; + + if (!strlen($url)) { + $url = '/'; + } + + $request = $this->_method . ' ' . $url . ' HTTP/' . $this->_http . "\r\n"; + + if (in_array($this->_method, $this->_bodyDisallowed) || + (0 == strlen($this->_body) && (HTTP_REQUEST_METHOD_POST != $this->_method || + (empty($this->_postData) && empty($this->_postFiles))))) + { + $this->removeHeader('Content-Type'); + } else { + if (empty($this->_requestHeaders['content-type'])) { + // Add default content-type + $this->addHeader('Content-Type', 'application/x-www-form-urlencoded'); + } elseif ('multipart/form-data' == $this->_requestHeaders['content-type']) { + $boundary = 'HTTP_Request_' . md5(uniqid('request') . microtime()); + $this->addHeader('Content-Type', 'multipart/form-data; boundary=' . $boundary); + } + } + + // Request Headers + if (!empty($this->_requestHeaders)) { + foreach ($this->_requestHeaders as $name => $value) { + $canonicalName = implode('-', array_map('ucfirst', explode('-', $name))); + $request .= $canonicalName . ': ' . $value . "\r\n"; + } + } + + // Method does not allow a body, simply add a final CRLF + if (in_array($this->_method, $this->_bodyDisallowed)) { + + $request .= "\r\n"; + + // Post data if it's an array + } elseif (HTTP_REQUEST_METHOD_POST == $this->_method && + (!empty($this->_postData) || !empty($this->_postFiles))) { + + // "normal" POST request + if (!isset($boundary)) { + $postdata = implode('&', array_map( + create_function('$a', 'return $a[0] . \'=\' . $a[1];'), + $this->_flattenArray('', $this->_postData) + )); + + // multipart request, probably with file uploads + } else { + $postdata = ''; + if (!empty($this->_postData)) { + $flatData = $this->_flattenArray('', $this->_postData); + foreach ($flatData as $item) { + $postdata .= '--' . $boundary . "\r\n"; + $postdata .= 'Content-Disposition: form-data; name="' . $item[0] . '"'; + $postdata .= "\r\n\r\n" . urldecode($item[1]) . "\r\n"; + } + } + foreach ($this->_postFiles as $name => $value) { + if (is_array($value['name'])) { + $varname = $name . ($this->_useBrackets? '[]': ''); + } else { + $varname = $name; + $value['name'] = array($value['name']); + } + foreach ($value['name'] as $key => $filename) { + $fp = fopen($filename, 'r'); + $basename = basename($filename); + $type = is_array($value['type'])? @$value['type'][$key]: $value['type']; + + $postdata .= '--' . $boundary . "\r\n"; + $postdata .= 'Content-Disposition: form-data; name="' . $varname . '"; filename="' . $basename . '"'; + $postdata .= "\r\nContent-Type: " . $type; + $postdata .= "\r\n\r\n" . fread($fp, filesize($filename)) . "\r\n"; + fclose($fp); + } + } + $postdata .= '--' . $boundary . "--\r\n"; + } + $request .= 'Content-Length: ' . + (HTTP_REQUEST_MBSTRING? mb_strlen($postdata, 'iso-8859-1'): strlen($postdata)) . + "\r\n\r\n"; + $request .= $postdata; + + // Explicitly set request body + } elseif (0 < strlen($this->_body)) { + + $request .= 'Content-Length: ' . + (HTTP_REQUEST_MBSTRING? mb_strlen($this->_body, 'iso-8859-1'): strlen($this->_body)) . + "\r\n\r\n"; + $request .= $this->_body; + + // No body: send a Content-Length header nonetheless (request #12900), + // but do that only for methods that require a body (bug #14740) + } else { + + if (in_array($this->_method, $this->_bodyRequired)) { + $request .= "Content-Length: 0\r\n"; + } + $request .= "\r\n"; + } + + return $request; + } + + /** + * Helper function to change the (probably multidimensional) associative array + * into the simple one. + * + * @param string name for item + * @param mixed item's values + * @return array array with the following items: array('item name', 'item value'); + * @access private + */ + function _flattenArray($name, $values) + { + if (!is_array($values)) { + return array(array($name, $values)); + } else { + $ret = array(); + foreach ($values as $k => $v) { + if (empty($name)) { + $newName = $k; + } elseif ($this->_useBrackets) { + $newName = $name . '[' . $k . ']'; + } else { + $newName = $name; + } + $ret = array_merge($ret, $this->_flattenArray($newName, $v)); + } + return $ret; + } + } + + + /** + * Adds a Listener to the list of listeners that are notified of + * the object's events + * + * Events sent by HTTP_Request object + * - 'connect': on connection to server + * - 'sentRequest': after the request was sent + * - 'disconnect': on disconnection from server + * + * Events sent by HTTP_Response object + * - 'gotHeaders': after receiving response headers (headers are passed in $data) + * - 'tick': on receiving a part of response body (the part is passed in $data) + * - 'gzTick': on receiving a gzip-encoded part of response body (ditto) + * - 'gotBody': after receiving the response body (passes the decoded body in $data if it was gzipped) + * + * @param HTTP_Request_Listener listener to attach + * @return boolean whether the listener was successfully attached + * @access public + */ + function attach(&$listener) + { + if (!is_a($listener, 'HTTP_Request_Listener')) { + return false; + } + $this->_listeners[$listener->getId()] =& $listener; + return true; + } + + + /** + * Removes a Listener from the list of listeners + * + * @param HTTP_Request_Listener listener to detach + * @return boolean whether the listener was successfully detached + * @access public + */ + function detach(&$listener) + { + if (!is_a($listener, 'HTTP_Request_Listener') || + !isset($this->_listeners[$listener->getId()])) { + return false; + } + unset($this->_listeners[$listener->getId()]); + return true; + } + + + /** + * Notifies all registered listeners of an event. + * + * @param string Event name + * @param mixed Additional data + * @access private + * @see HTTP_Request::attach() + */ + function _notify($event, $data = null) + { + foreach (array_keys($this->_listeners) as $id) { + $this->_listeners[$id]->update($this, $event, $data); + } + } +} + + +/** + * Response class to complement the Request class + * + * @category HTTP + * @package HTTP_Request + * @author Richard Heyes + * @author Alexey Borzov + * @version Release: 1.4.4 + */ +class HTTP_Response +{ + /** + * Socket object + * @var Net_Socket + */ + var $_sock; + + /** + * Protocol + * @var string + */ + var $_protocol; + + /** + * Return code + * @var string + */ + var $_code; + + /** + * Response reason phrase + * @var string + */ + var $_reason; + + /** + * Response headers + * @var array + */ + var $_headers; + + /** + * Cookies set in response + * @var array + */ + var $_cookies; + + /** + * Response body + * @var string + */ + var $_body = ''; + + /** + * Used by _readChunked(): remaining length of the current chunk + * @var string + */ + var $_chunkLength = 0; + + /** + * Attached listeners + * @var array + */ + var $_listeners = array(); + + /** + * Bytes left to read from message-body + * @var null|int + */ + var $_toRead; + + /** + * Constructor + * + * @param Net_Socket socket to read the response from + * @param array listeners attached to request + */ + function HTTP_Response(&$sock, &$listeners) + { + $this->_sock =& $sock; + $this->_listeners =& $listeners; + } + + + /** + * Processes a HTTP response + * + * This extracts response code, headers, cookies and decodes body if it + * was encoded in some way + * + * @access public + * @param bool Whether to store response body in object property, set + * this to false if downloading a LARGE file and using a Listener. + * This is assumed to be true if body is gzip-encoded. + * @param bool Whether the response can actually have a message-body. + * Will be set to false for HEAD requests. + * @throws PEAR_Error + * @return mixed true on success, PEAR_Error in case of malformed response + */ + function process($saveBody = true, $canHaveBody = true) + { + do { + $line = $this->_sock->readLine(); + if (!preg_match('!^(HTTP/\d\.\d) (\d{3})(?: (.+))?!', $line, $s)) { + return PEAR::raiseError('Malformed response', HTTP_REQUEST_ERROR_RESPONSE); + } else { + $this->_protocol = $s[1]; + $this->_code = intval($s[2]); + $this->_reason = empty($s[3])? null: $s[3]; + } + while ('' !== ($header = $this->_sock->readLine())) { + $this->_processHeader($header); + } + } while (100 == $this->_code); + + $this->_notify('gotHeaders', $this->_headers); + + // RFC 2616, section 4.4: + // 1. Any response message which "MUST NOT" include a message-body ... + // is always terminated by the first empty line after the header fields + // 3. ... If a message is received with both a + // Transfer-Encoding header field and a Content-Length header field, + // the latter MUST be ignored. + $canHaveBody = $canHaveBody && $this->_code >= 200 && + $this->_code != 204 && $this->_code != 304; + + // If response body is present, read it and decode + $chunked = isset($this->_headers['transfer-encoding']) && ('chunked' == $this->_headers['transfer-encoding']); + $gzipped = isset($this->_headers['content-encoding']) && ('gzip' == $this->_headers['content-encoding']); + $hasBody = false; + if ($canHaveBody && ($chunked || !isset($this->_headers['content-length']) || + 0 != $this->_headers['content-length'])) + { + if ($chunked || !isset($this->_headers['content-length'])) { + $this->_toRead = null; + } else { + $this->_toRead = $this->_headers['content-length']; + } + while (!$this->_sock->eof() && (is_null($this->_toRead) || 0 < $this->_toRead)) { + if ($chunked) { + $data = $this->_readChunked(); + } elseif (is_null($this->_toRead)) { + $data = $this->_sock->read(4096); + } else { + $data = $this->_sock->read(min(4096, $this->_toRead)); + $this->_toRead -= HTTP_REQUEST_MBSTRING? mb_strlen($data, 'iso-8859-1'): strlen($data); + } + if ('' == $data && (!$this->_chunkLength || $this->_sock->eof())) { + break; + } else { + $hasBody = true; + if ($saveBody || $gzipped) { + $this->_body .= $data; + } + $this->_notify($gzipped? 'gzTick': 'tick', $data); + } + } + } + + if ($hasBody) { + // Uncompress the body if needed + if ($gzipped) { + $body = $this->_decodeGzip($this->_body); + if (PEAR::isError($body)) { + return $body; + } + $this->_body = $body; + $this->_notify('gotBody', $this->_body); + } else { + $this->_notify('gotBody'); + } + } + return true; + } + + + /** + * Processes the response header + * + * @access private + * @param string HTTP header + */ + function _processHeader($header) + { + if (false === strpos($header, ':')) { + return; + } + list($headername, $headervalue) = explode(':', $header, 2); + $headername = strtolower($headername); + $headervalue = ltrim($headervalue); + + if ('set-cookie' != $headername) { + if (isset($this->_headers[$headername])) { + $this->_headers[$headername] .= ',' . $headervalue; + } else { + $this->_headers[$headername] = $headervalue; + } + } else { + $this->_parseCookie($headervalue); + } + } + + + /** + * Parse a Set-Cookie header to fill $_cookies array + * + * @access private + * @param string value of Set-Cookie header + */ + function _parseCookie($headervalue) + { + $cookie = array( + 'expires' => null, + 'domain' => null, + 'path' => null, + 'secure' => false + ); + + // Only a name=value pair + if (!strpos($headervalue, ';')) { + $pos = strpos($headervalue, '='); + $cookie['name'] = trim(substr($headervalue, 0, $pos)); + $cookie['value'] = trim(substr($headervalue, $pos + 1)); + + // Some optional parameters are supplied + } else { + $elements = explode(';', $headervalue); + $pos = strpos($elements[0], '='); + $cookie['name'] = trim(substr($elements[0], 0, $pos)); + $cookie['value'] = trim(substr($elements[0], $pos + 1)); + + for ($i = 1; $i < count($elements); $i++) { + if (false === strpos($elements[$i], '=')) { + $elName = trim($elements[$i]); + $elValue = null; + } else { + list ($elName, $elValue) = array_map('trim', explode('=', $elements[$i])); + } + $elName = strtolower($elName); + if ('secure' == $elName) { + $cookie['secure'] = true; + } elseif ('expires' == $elName) { + $cookie['expires'] = str_replace('"', '', $elValue); + } elseif ('path' == $elName || 'domain' == $elName) { + $cookie[$elName] = urldecode($elValue); + } else { + $cookie[$elName] = $elValue; + } + } + } + $this->_cookies[] = $cookie; + } + + + /** + * Read a part of response body encoded with chunked Transfer-Encoding + * + * @access private + * @return string + */ + function _readChunked() + { + // at start of the next chunk? + if (0 == $this->_chunkLength) { + $line = $this->_sock->readLine(); + if (preg_match('/^([0-9a-f]+)/i', $line, $matches)) { + $this->_chunkLength = hexdec($matches[1]); + // Chunk with zero length indicates the end + if (0 == $this->_chunkLength) { + $this->_sock->readLine(); // make this an eof() + return ''; + } + } else { + return ''; + } + } + $data = $this->_sock->read($this->_chunkLength); + $this->_chunkLength -= HTTP_REQUEST_MBSTRING? mb_strlen($data, 'iso-8859-1'): strlen($data); + if (0 == $this->_chunkLength) { + $this->_sock->readLine(); // Trailing CRLF + } + return $data; + } + + + /** + * Notifies all registered listeners of an event. + * + * @param string Event name + * @param mixed Additional data + * @access private + * @see HTTP_Request::_notify() + */ + function _notify($event, $data = null) + { + foreach (array_keys($this->_listeners) as $id) { + $this->_listeners[$id]->update($this, $event, $data); + } + } + + + /** + * Decodes the message-body encoded by gzip + * + * The real decoding work is done by gzinflate() built-in function, this + * method only parses the header and checks data for compliance with + * RFC 1952 + * + * @access private + * @param string gzip-encoded data + * @return string decoded data + */ + function _decodeGzip($data) + { + if (HTTP_REQUEST_MBSTRING) { + $oldEncoding = mb_internal_encoding(); + mb_internal_encoding('iso-8859-1'); + } + $length = strlen($data); + // If it doesn't look like gzip-encoded data, don't bother + if (18 > $length || strcmp(substr($data, 0, 2), "\x1f\x8b")) { + return $data; + } + $method = ord(substr($data, 2, 1)); + if (8 != $method) { + return PEAR::raiseError('_decodeGzip(): unknown compression method', HTTP_REQUEST_ERROR_GZIP_METHOD); + } + $flags = ord(substr($data, 3, 1)); + if ($flags & 224) { + return PEAR::raiseError('_decodeGzip(): reserved bits are set', HTTP_REQUEST_ERROR_GZIP_DATA); + } + + // header is 10 bytes minimum. may be longer, though. + $headerLength = 10; + // extra fields, need to skip 'em + if ($flags & 4) { + if ($length - $headerLength - 2 < 8) { + return PEAR::raiseError('_decodeGzip(): data too short', HTTP_REQUEST_ERROR_GZIP_DATA); + } + $extraLength = unpack('v', substr($data, 10, 2)); + if ($length - $headerLength - 2 - $extraLength[1] < 8) { + return PEAR::raiseError('_decodeGzip(): data too short', HTTP_REQUEST_ERROR_GZIP_DATA); + } + $headerLength += $extraLength[1] + 2; + } + // file name, need to skip that + if ($flags & 8) { + if ($length - $headerLength - 1 < 8) { + return PEAR::raiseError('_decodeGzip(): data too short', HTTP_REQUEST_ERROR_GZIP_DATA); + } + $filenameLength = strpos(substr($data, $headerLength), chr(0)); + if (false === $filenameLength || $length - $headerLength - $filenameLength - 1 < 8) { + return PEAR::raiseError('_decodeGzip(): data too short', HTTP_REQUEST_ERROR_GZIP_DATA); + } + $headerLength += $filenameLength + 1; + } + // comment, need to skip that also + if ($flags & 16) { + if ($length - $headerLength - 1 < 8) { + return PEAR::raiseError('_decodeGzip(): data too short', HTTP_REQUEST_ERROR_GZIP_DATA); + } + $commentLength = strpos(substr($data, $headerLength), chr(0)); + if (false === $commentLength || $length - $headerLength - $commentLength - 1 < 8) { + return PEAR::raiseError('_decodeGzip(): data too short', HTTP_REQUEST_ERROR_GZIP_DATA); + } + $headerLength += $commentLength + 1; + } + // have a CRC for header. let's check + if ($flags & 1) { + if ($length - $headerLength - 2 < 8) { + return PEAR::raiseError('_decodeGzip(): data too short', HTTP_REQUEST_ERROR_GZIP_DATA); + } + $crcReal = 0xffff & crc32(substr($data, 0, $headerLength)); + $crcStored = unpack('v', substr($data, $headerLength, 2)); + if ($crcReal != $crcStored[1]) { + return PEAR::raiseError('_decodeGzip(): header CRC check failed', HTTP_REQUEST_ERROR_GZIP_CRC); + } + $headerLength += 2; + } + // unpacked data CRC and size at the end of encoded data + $tmp = unpack('V2', substr($data, -8)); + $dataCrc = $tmp[1]; + $dataSize = $tmp[2]; + + // finally, call the gzinflate() function + // don't pass $dataSize to gzinflate, see bugs #13135, #14370 + $unpacked = gzinflate(substr($data, $headerLength, -8)); + if (false === $unpacked) { + return PEAR::raiseError('_decodeGzip(): gzinflate() call failed', HTTP_REQUEST_ERROR_GZIP_READ); + } elseif ($dataSize != strlen($unpacked)) { + return PEAR::raiseError('_decodeGzip(): data size check failed', HTTP_REQUEST_ERROR_GZIP_READ); + } elseif ((0xffffffff & $dataCrc) != (0xffffffff & crc32($unpacked))) { + return PEAR::raiseError('_decodeGzip(): data CRC check failed', HTTP_REQUEST_ERROR_GZIP_CRC); + } + if (HTTP_REQUEST_MBSTRING) { + mb_internal_encoding($oldEncoding); + } + return $unpacked; + } +} // End class HTTP_Response +?> diff --git a/oss/vtiger/trunk/vtlib/thirdparty/network/Request/Listener.php b/oss/vtiger/trunk/vtlib/thirdparty/network/Request/Listener.php new file mode 100644 index 00000000..c9095ebc --- /dev/null +++ b/oss/vtiger/trunk/vtlib/thirdparty/network/Request/Listener.php @@ -0,0 +1,106 @@ + + * @copyright 2002-2007 Richard Heyes + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: Listener.php,v 1.3 2007/05/18 10:33:31 avb Exp $ + * @link http://pear.php.net/package/HTTP_Request/ + */ + +/** + * Listener for HTTP_Request and HTTP_Response objects + * + * This class implements the Observer part of a Subject-Observer + * design pattern. + * + * @category HTTP + * @package HTTP_Request + * @author Alexey Borzov + * @version Release: 1.4.4 + */ +class HTTP_Request_Listener +{ + /** + * A listener's identifier + * @var string + */ + var $_id; + + /** + * Constructor, sets the object's identifier + * + * @access public + */ + function HTTP_Request_Listener() + { + $this->_id = md5(uniqid('http_request_', 1)); + } + + + /** + * Returns the listener's identifier + * + * @access public + * @return string + */ + function getId() + { + return $this->_id; + } + + + /** + * This method is called when Listener is notified of an event + * + * @access public + * @param object an object the listener is attached to + * @param string Event name + * @param mixed Additional data + * @abstract + */ + function update(&$subject, $event, $data = null) + { + echo "Notified of event: '$event'\n"; + if (null !== $data) { + echo "Additional data: "; + var_dump($data); + } + } +} +?> diff --git a/oss/vtiger/trunk/vtlib/thirdparty/parser/feed/simplepie.inc b/oss/vtiger/trunk/vtlib/thirdparty/parser/feed/simplepie.inc new file mode 100644 index 00000000..a7186fe0 --- /dev/null +++ b/oss/vtiger/trunk/vtlib/thirdparty/parser/feed/simplepie.inc @@ -0,0 +1,13675 @@ +' . SIMPLEPIE_NAME . ''); + +/** + * No Autodiscovery + * @see SimplePie::set_autodiscovery_level() + */ +define('SIMPLEPIE_LOCATOR_NONE', 0); + +/** + * Feed Link Element Autodiscovery + * @see SimplePie::set_autodiscovery_level() + */ +define('SIMPLEPIE_LOCATOR_AUTODISCOVERY', 1); + +/** + * Local Feed Extension Autodiscovery + * @see SimplePie::set_autodiscovery_level() + */ +define('SIMPLEPIE_LOCATOR_LOCAL_EXTENSION', 2); + +/** + * Local Feed Body Autodiscovery + * @see SimplePie::set_autodiscovery_level() + */ +define('SIMPLEPIE_LOCATOR_LOCAL_BODY', 4); + +/** + * Remote Feed Extension Autodiscovery + * @see SimplePie::set_autodiscovery_level() + */ +define('SIMPLEPIE_LOCATOR_REMOTE_EXTENSION', 8); + +/** + * Remote Feed Body Autodiscovery + * @see SimplePie::set_autodiscovery_level() + */ +define('SIMPLEPIE_LOCATOR_REMOTE_BODY', 16); + +/** + * All Feed Autodiscovery + * @see SimplePie::set_autodiscovery_level() + */ +define('SIMPLEPIE_LOCATOR_ALL', 31); + +/** + * No known feed type + */ +define('SIMPLEPIE_TYPE_NONE', 0); + +/** + * RSS 0.90 + */ +define('SIMPLEPIE_TYPE_RSS_090', 1); + +/** + * RSS 0.91 (Netscape) + */ +define('SIMPLEPIE_TYPE_RSS_091_NETSCAPE', 2); + +/** + * RSS 0.91 (Userland) + */ +define('SIMPLEPIE_TYPE_RSS_091_USERLAND', 4); + +/** + * RSS 0.91 (both Netscape and Userland) + */ +define('SIMPLEPIE_TYPE_RSS_091', 6); + +/** + * RSS 0.92 + */ +define('SIMPLEPIE_TYPE_RSS_092', 8); + +/** + * RSS 0.93 + */ +define('SIMPLEPIE_TYPE_RSS_093', 16); + +/** + * RSS 0.94 + */ +define('SIMPLEPIE_TYPE_RSS_094', 32); + +/** + * RSS 1.0 + */ +define('SIMPLEPIE_TYPE_RSS_10', 64); + +/** + * RSS 2.0 + */ +define('SIMPLEPIE_TYPE_RSS_20', 128); + +/** + * RDF-based RSS + */ +define('SIMPLEPIE_TYPE_RSS_RDF', 65); + +/** + * Non-RDF-based RSS (truly intended as syndication format) + */ +define('SIMPLEPIE_TYPE_RSS_SYNDICATION', 190); + +/** + * All RSS + */ +define('SIMPLEPIE_TYPE_RSS_ALL', 255); + +/** + * Atom 0.3 + */ +define('SIMPLEPIE_TYPE_ATOM_03', 256); + +/** + * Atom 1.0 + */ +define('SIMPLEPIE_TYPE_ATOM_10', 512); + +/** + * All Atom + */ +define('SIMPLEPIE_TYPE_ATOM_ALL', 768); + +/** + * All feed types + */ +define('SIMPLEPIE_TYPE_ALL', 1023); + +/** + * No construct + */ +define('SIMPLEPIE_CONSTRUCT_NONE', 0); + +/** + * Text construct + */ +define('SIMPLEPIE_CONSTRUCT_TEXT', 1); + +/** + * HTML construct + */ +define('SIMPLEPIE_CONSTRUCT_HTML', 2); + +/** + * XHTML construct + */ +define('SIMPLEPIE_CONSTRUCT_XHTML', 4); + +/** + * base64-encoded construct + */ +define('SIMPLEPIE_CONSTRUCT_BASE64', 8); + +/** + * IRI construct + */ +define('SIMPLEPIE_CONSTRUCT_IRI', 16); + +/** + * A construct that might be HTML + */ +define('SIMPLEPIE_CONSTRUCT_MAYBE_HTML', 32); + +/** + * All constructs + */ +define('SIMPLEPIE_CONSTRUCT_ALL', 63); + +/** + * PCRE for HTML attributes + */ +define('SIMPLEPIE_PCRE_HTML_ATTRIBUTE', '((?:[\x09\x0A\x0B\x0C\x0D\x20]+[^\x09\x0A\x0B\x0C\x0D\x20\x2F\x3E][^\x09\x0A\x0B\x0C\x0D\x20\x2F\x3D\x3E]*(?:[\x09\x0A\x0B\x0C\x0D\x20]*=[\x09\x0A\x0B\x0C\x0D\x20]*(?:"(?:[^"]*)"|\'(?:[^\']*)\'|(?:[^\x09\x0A\x0B\x0C\x0D\x20\x22\x27\x3E][^\x09\x0A\x0B\x0C\x0D\x20\x3E]*)?))?)*)[\x09\x0A\x0B\x0C\x0D\x20]*'); + +/** + * PCRE for XML attributes + */ +define('SIMPLEPIE_PCRE_XML_ATTRIBUTE', '((?:\s+(?:(?:[^\s:]+:)?[^\s:]+)\s*=\s*(?:"(?:[^"]*)"|\'(?:[^\']*)\'))*)\s*'); + +/** + * XML Namespace + */ +define('SIMPLEPIE_NAMESPACE_XML', 'http://www.w3.org/XML/1998/namespace'); + +/** + * Atom 1.0 Namespace + */ +define('SIMPLEPIE_NAMESPACE_ATOM_10', 'http://www.w3.org/2005/Atom'); + +/** + * Atom 0.3 Namespace + */ +define('SIMPLEPIE_NAMESPACE_ATOM_03', 'http://purl.org/atom/ns#'); + +/** + * RDF Namespace + */ +define('SIMPLEPIE_NAMESPACE_RDF', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#'); + +/** + * RSS 0.90 Namespace + */ +define('SIMPLEPIE_NAMESPACE_RSS_090', 'http://my.netscape.com/rdf/simple/0.9/'); + +/** + * RSS 1.0 Namespace + */ +define('SIMPLEPIE_NAMESPACE_RSS_10', 'http://purl.org/rss/1.0/'); + +/** + * RSS 1.0 Content Module Namespace + */ +define('SIMPLEPIE_NAMESPACE_RSS_10_MODULES_CONTENT', 'http://purl.org/rss/1.0/modules/content/'); + +/** + * RSS 2.0 Namespace + * (Stupid, I know, but I'm certain it will confuse people less with support.) + */ +define('SIMPLEPIE_NAMESPACE_RSS_20', ''); + +/** + * DC 1.0 Namespace + */ +define('SIMPLEPIE_NAMESPACE_DC_10', 'http://purl.org/dc/elements/1.0/'); + +/** + * DC 1.1 Namespace + */ +define('SIMPLEPIE_NAMESPACE_DC_11', 'http://purl.org/dc/elements/1.1/'); + +/** + * W3C Basic Geo (WGS84 lat/long) Vocabulary Namespace + */ +define('SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO', 'http://www.w3.org/2003/01/geo/wgs84_pos#'); + +/** + * GeoRSS Namespace + */ +define('SIMPLEPIE_NAMESPACE_GEORSS', 'http://www.georss.org/georss'); + +/** + * Media RSS Namespace + */ +define('SIMPLEPIE_NAMESPACE_MEDIARSS', 'http://search.yahoo.com/mrss/'); + +/** + * Wrong Media RSS Namespace + */ +define('SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG', 'http://search.yahoo.com/mrss'); + +/** + * iTunes RSS Namespace + */ +define('SIMPLEPIE_NAMESPACE_ITUNES', 'http://www.itunes.com/dtds/podcast-1.0.dtd'); + +/** + * XHTML Namespace + */ +define('SIMPLEPIE_NAMESPACE_XHTML', 'http://www.w3.org/1999/xhtml'); + +/** + * IANA Link Relations Registry + */ +define('SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY', 'http://www.iana.org/assignments/relation/'); + +/** + * Whether we're running on PHP5 + */ +define('SIMPLEPIE_PHP5', version_compare(PHP_VERSION, '5.0.0', '>=')); + +/** + * No file source + */ +define('SIMPLEPIE_FILE_SOURCE_NONE', 0); + +/** + * Remote file source + */ +define('SIMPLEPIE_FILE_SOURCE_REMOTE', 1); + +/** + * Local file source + */ +define('SIMPLEPIE_FILE_SOURCE_LOCAL', 2); + +/** + * fsockopen() file source + */ +define('SIMPLEPIE_FILE_SOURCE_FSOCKOPEN', 4); + +/** + * cURL file source + */ +define('SIMPLEPIE_FILE_SOURCE_CURL', 8); + +/** + * file_get_contents() file source + */ +define('SIMPLEPIE_FILE_SOURCE_FILE_GET_CONTENTS', 16); + +/** + * SimplePie + * + * @package SimplePie + * @version "Razzleberry" + * @copyright 2004-2007 Ryan Parman, Geoffrey Sneddon + * @author Ryan Parman + * @author Geoffrey Sneddon + * @todo Option for type of fetching (cache, not modified header, fetch, etc.) + */ +class SimplePie +{ + /** + * @var array Raw data + * @access private + */ + var $data = array(); + + /** + * @var mixed Error string + * @access private + */ + var $error; + + /** + * @var object Instance of SimplePie_Sanitize (or other class) + * @see SimplePie::set_sanitize_class() + * @access private + */ + var $sanitize; + + /** + * @var string SimplePie Useragent + * @see SimplePie::set_useragent() + * @access private + */ + var $useragent = SIMPLEPIE_USERAGENT; + + /** + * @var string Feed URL + * @see SimplePie::set_feed_url() + * @access private + */ + var $feed_url; + + /** + * @var object Instance of SimplePie_File to use as a feed + * @see SimplePie::set_file() + * @access private + */ + var $file; + + /** + * @var string Raw feed data + * @see SimplePie::set_raw_data() + * @access private + */ + var $raw_data; + + /** + * @var int Timeout for fetching remote files + * @see SimplePie::set_timeout() + * @access private + */ + var $timeout = 10; + + /** + * @var bool Forces fsockopen() to be used for remote files instead + * of cURL, even if a new enough version is installed + * @see SimplePie::force_fsockopen() + * @access private + */ + var $force_fsockopen = false; + + /** + * @var bool Force the given data/URL to be treated as a feed no matter what + * it appears like + * @see SimplePie::force_feed() + * @access private + */ + var $force_feed = false; + + /** + * @var bool Enable/Disable XML dump + * @see SimplePie::enable_xml_dump() + * @access private + */ + var $xml_dump = false; + + /** + * @var bool Enable/Disable Caching + * @see SimplePie::enable_cache() + * @access private + */ + var $cache = true; + + /** + * @var int Cache duration (in seconds) + * @see SimplePie::set_cache_duration() + * @access private + */ + var $cache_duration = 3600; + + /** + * @var int Auto-discovery cache duration (in seconds) + * @see SimplePie::set_autodiscovery_cache_duration() + * @access private + */ + var $autodiscovery_cache_duration = 604800; // 7 Days. + + /** + * @var string Cache location (relative to executing script) + * @see SimplePie::set_cache_location() + * @access private + */ + var $cache_location = './cache'; + + /** + * @var string Function that creates the cache filename + * @see SimplePie::set_cache_name_function() + * @access private + */ + var $cache_name_function = 'md5'; + + /** + * @var bool Reorder feed by date descending + * @see SimplePie::enable_order_by_date() + * @access private + */ + var $order_by_date = true; + + /** + * @var mixed Force input encoding to be set to the follow value + * (false, or anything type-cast to false, disables this feature) + * @see SimplePie::set_input_encoding() + * @access private + */ + var $input_encoding = false; + + /** + * @var int Feed Autodiscovery Level + * @see SimplePie::set_autodiscovery_level() + * @access private + */ + var $autodiscovery = SIMPLEPIE_LOCATOR_ALL; + + /** + * @var string Class used for caching feeds + * @see SimplePie::set_cache_class() + * @access private + */ + var $cache_class = 'SimplePie_Cache'; + + /** + * @var string Class used for locating feeds + * @see SimplePie::set_locator_class() + * @access private + */ + var $locator_class = 'SimplePie_Locator'; + + /** + * @var string Class used for parsing feeds + * @see SimplePie::set_parser_class() + * @access private + */ + var $parser_class = 'SimplePie_Parser'; + + /** + * @var string Class used for fetching feeds + * @see SimplePie::set_file_class() + * @access private + */ + var $file_class = 'SimplePie_File'; + + /** + * @var string Class used for items + * @see SimplePie::set_item_class() + * @access private + */ + var $item_class = 'SimplePie_Item'; + + /** + * @var string Class used for authors + * @see SimplePie::set_author_class() + * @access private + */ + var $author_class = 'SimplePie_Author'; + + /** + * @var string Class used for categories + * @see SimplePie::set_category_class() + * @access private + */ + var $category_class = 'SimplePie_Category'; + + /** + * @var string Class used for enclosures + * @see SimplePie::set_enclosures_class() + * @access private + */ + var $enclosure_class = 'SimplePie_Enclosure'; + + /** + * @var string Class used for Media RSS captions + * @see SimplePie::set_caption_class() + * @access private + */ + var $caption_class = 'SimplePie_Caption'; + + /** + * @var string Class used for Media RSS + * @see SimplePie::set_copyright_class() + * @access private + */ + var $copyright_class = 'SimplePie_Copyright'; + + /** + * @var string Class used for Media RSS + * @see SimplePie::set_credit_class() + * @access private + */ + var $credit_class = 'SimplePie_Credit'; + + /** + * @var string Class used for Media RSS + * @see SimplePie::set_rating_class() + * @access private + */ + var $rating_class = 'SimplePie_Rating'; + + /** + * @var string Class used for Media RSS + * @see SimplePie::set_restriction_class() + * @access private + */ + var $restriction_class = 'SimplePie_Restriction'; + + /** + * @var string Class used for content-type sniffing + * @see SimplePie::set_content_type_sniffer_class() + * @access private + */ + var $content_type_sniffer_class = 'SimplePie_Content_Type_Sniffer'; + + /** + * @var string Class used for item sources. + * @see SimplePie::set_source_class() + * @access private + */ + var $source_class = 'SimplePie_Source'; + + /** + * @var mixed Set javascript query string parameter (false, or + * anything type-cast to false, disables this feature) + * @see SimplePie::set_javascript() + * @access private + */ + var $javascript = 'js'; + + /** + * @var int Maximum number of feeds to check with autodiscovery + * @see SimplePie::set_max_checked_feeds() + * @access private + */ + var $max_checked_feeds = 10; + + /** + * @var string Web-accessible path to the handler_favicon.php file. + * @see SimplePie::set_favicon_handler() + * @access private + */ + var $favicon_handler = ''; + + /** + * @var string Web-accessible path to the handler_image.php file. + * @see SimplePie::set_image_handler() + * @access private + */ + var $image_handler = ''; + + /** + * @var array Stores the URLs when multiple feeds are being initialized. + * @see SimplePie::set_feed_url() + * @access private + */ + var $multifeed_url = array(); + + /** + * @var array Stores SimplePie objects when multiple feeds initialized. + * @access private + */ + var $multifeed_objects = array(); + + /** + * @var array Stores the get_object_vars() array for use with multifeeds. + * @see SimplePie::set_feed_url() + * @access private + */ + var $config_settings = null; + + /** + * @var integer Stores the number of items to return per-feed with multifeeds. + * @see SimplePie::set_item_limit() + * @access private + */ + var $item_limit = 0; + + /** + * @var array Stores the default attributes to be stripped by strip_attributes(). + * @see SimplePie::strip_attributes() + * @access private + */ + var $strip_attributes = array('bgsound', 'class', 'expr', 'id', 'style', 'onclick', 'onerror', 'onfinish', 'onmouseover', 'onmouseout', 'onfocus', 'onblur', 'lowsrc', 'dynsrc'); + + /** + * @var array Stores the default tags to be stripped by strip_htmltags(). + * @see SimplePie::strip_htmltags() + * @access private + */ + var $strip_htmltags = array('base', 'blink', 'body', 'doctype', 'embed', 'font', 'form', 'frame', 'frameset', 'html', 'iframe', 'input', 'marquee', 'meta', 'noscript', 'object', 'param', 'script', 'style'); + + /** + * The SimplePie class contains feed level data and options + * + * There are two ways that you can create a new SimplePie object. The first + * is by passing a feed URL as a parameter to the SimplePie constructor + * (as well as optionally setting the cache location and cache expiry). This + * will initialise the whole feed with all of the default settings, and you + * can begin accessing methods and properties immediately. + * + * The second way is to create the SimplePie object with no parameters + * at all. This will enable you to set configuration options. After setting + * them, you must initialise the feed using $feed->init(). At that point the + * object's methods and properties will be available to you. This format is + * what is used throughout this documentation. + * + * @access public + * @since 1.0 Preview Release + * @param string $feed_url This is the URL you want to parse. + * @param string $cache_location This is where you want the cache to be stored. + * @param int $cache_duration This is the number of seconds that you want to store the cache file for. + */ + function SimplePie($feed_url = null, $cache_location = null, $cache_duration = null) + { + // Other objects, instances created here so we can set options on them + $this->sanitize =& new SimplePie_Sanitize; + + // Set options if they're passed to the constructor + if ($cache_location !== null) + { + $this->set_cache_location($cache_location); + } + + if ($cache_duration !== null) + { + $this->set_cache_duration($cache_duration); + } + + // Only init the script if we're passed a feed URL + if ($feed_url !== null) + { + $this->set_feed_url($feed_url); + $this->init(); + } + } + + /** + * Used for converting object to a string + */ + function __toString() + { + return md5(serialize($this->data)); + } + + /** + * Remove items that link back to this before destroying this object + */ + function __destruct() + { + if (!empty($this->data['items'])) + { + foreach ($this->data['items'] as $item) + { + $item->__destruct(); + } + unset($this->data['items']); + } + if (!empty($this->data['ordered_items'])) + { + foreach ($this->data['ordered_items'] as $item) + { + $item->__destruct(); + } + unset($this->data['ordered_items']); + } + } + + /** + * Force the given data/URL to be treated as a feed no matter what it + * appears like + * + * @access public + * @since 1.1 + * @param bool $enable Force the given data/URL to be treated as a feed + */ + function force_feed($enable = false) + { + $this->force_feed = (bool) $enable; + } + + /** + * This is the URL of the feed you want to parse. + * + * This allows you to enter the URL of the feed you want to parse, or the + * website you want to try to use auto-discovery on. This takes priority + * over any set raw data. + * + * You can set multiple feeds to mash together by passing an array instead + * of a string for the $url. Remember that with each additional feed comes + * additional processing and resources. + * + * @access public + * @since 1.0 Preview Release + * @param mixed $url This is the URL (or array of URLs) that you want to parse. + * @see SimplePie::set_raw_data() + */ + function set_feed_url($url) + { + if (is_array($url)) + { + $this->multifeed_url = array(); + foreach ($url as $value) + { + $this->multifeed_url[] = SimplePie_Misc::fix_protocol($value, 1); + } + } + else + { + $this->feed_url = SimplePie_Misc::fix_protocol($url, 1); + } + } + + /** + * Provides an instance of SimplePie_File to use as a feed + * + * @access public + * @param object &$file Instance of SimplePie_File (or subclass) + * @return bool True on success, false on failure + */ + function set_file(&$file) + { + if (is_a($file, 'SimplePie_File')) + { + $this->feed_url = $file->url; + $this->file =& $file; + return true; + } + return false; + } + + /** + * Allows you to use a string of RSS/Atom data instead of a remote feed. + * + * If you have a feed available as a string in PHP, you can tell SimplePie + * to parse that data string instead of a remote feed. Any set feed URL + * takes precedence. + * + * @access public + * @since 1.0 Beta 3 + * @param string $data RSS or Atom data as a string. + * @see SimplePie::set_feed_url() + */ + function set_raw_data($data) + { + $this->raw_data = $data; + } + + /** + * Allows you to override the default timeout for fetching remote feeds. + * + * This allows you to change the maximum time the feed's server to respond + * and send the feed back. + * + * @access public + * @since 1.0 Beta 3 + * @param int $timeout The maximum number of seconds to spend waiting to retrieve a feed. + */ + function set_timeout($timeout = 10) + { + $this->timeout = (int) $timeout; + } + + /** + * Forces SimplePie to use fsockopen() instead of the preferred cURL + * functions. + * + * @access public + * @since 1.0 Beta 3 + * @param bool $enable Force fsockopen() to be used + */ + function force_fsockopen($enable = false) + { + $this->force_fsockopen = (bool) $enable; + } + + /** + * Outputs the raw XML content of the feed, after it has gone through + * SimplePie's filters. + * + * Used only for debugging, this function will output the XML content as + * text/xml. When SimplePie reads in a feed, it does a bit of cleaning up + * before trying to parse it. Many parts of the feed are re-written in + * memory, and in the end, you have a parsable feed. XML dump shows you the + * actual XML that SimplePie tries to parse, which may or may not be very + * different from the original feed. + * + * @access public + * @since 1.0 Preview Release + * @param bool $enable Enable XML dump + */ + function enable_xml_dump($enable = false) + { + $this->xml_dump = (bool) $enable; + } + + /** + * Enables/disables caching in SimplePie. + * + * This option allows you to disable caching all-together in SimplePie. + * However, disabling the cache can lead to longer load times. + * + * @access public + * @since 1.0 Preview Release + * @param bool $enable Enable caching + */ + function enable_cache($enable = true) + { + $this->cache = (bool) $enable; + } + + /** + * Set the length of time (in seconds) that the contents of a feed + * will be cached. + * + * @access public + * @param int $seconds The feed content cache duration. + */ + function set_cache_duration($seconds = 3600) + { + $this->cache_duration = (int) $seconds; + } + + /** + * Set the length of time (in seconds) that the autodiscovered feed + * URL will be cached. + * + * @access public + * @param int $seconds The autodiscovered feed URL cache duration. + */ + function set_autodiscovery_cache_duration($seconds = 604800) + { + $this->autodiscovery_cache_duration = (int) $seconds; + } + + /** + * Set the file system location where the cached files should be stored. + * + * @access public + * @param string $location The file system location. + */ + function set_cache_location($location = './cache') + { + $this->cache_location = (string) $location; + } + + /** + * Determines whether feed items should be sorted into reverse chronological order. + * + * @access public + * @param bool $enable Sort as reverse chronological order. + */ + function enable_order_by_date($enable = true) + { + $this->order_by_date = (bool) $enable; + } + + /** + * Allows you to override the character encoding reported by the feed. + * + * @access public + * @param string $encoding Character encoding. + */ + function set_input_encoding($encoding = false) + { + if ($encoding) + { + $this->input_encoding = (string) $encoding; + } + else + { + $this->input_encoding = false; + } + } + + /** + * Set how much feed autodiscovery to do + * + * @access public + * @see SIMPLEPIE_LOCATOR_NONE + * @see SIMPLEPIE_LOCATOR_AUTODISCOVERY + * @see SIMPLEPIE_LOCATOR_LOCAL_EXTENSION + * @see SIMPLEPIE_LOCATOR_LOCAL_BODY + * @see SIMPLEPIE_LOCATOR_REMOTE_EXTENSION + * @see SIMPLEPIE_LOCATOR_REMOTE_BODY + * @see SIMPLEPIE_LOCATOR_ALL + * @param int $level Feed Autodiscovery Level (level can be a + * combination of the above constants, see bitwise OR operator) + */ + function set_autodiscovery_level($level = SIMPLEPIE_LOCATOR_ALL) + { + $this->autodiscovery = (int) $level; + } + + /** + * Allows you to change which class SimplePie uses for caching. + * Useful when you are overloading or extending SimplePie's default classes. + * + * @access public + * @param string $class Name of custom class. + * @link http://php.net/manual/en/keyword.extends.php PHP4 extends documentation + * @link http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.extends PHP5 extends documentation + */ + function set_cache_class($class = 'SimplePie_Cache') + { + if (SimplePie_Misc::is_subclass_of($class, 'SimplePie_Cache')) + { + $this->cache_class = $class; + return true; + } + return false; + } + + /** + * Allows you to change which class SimplePie uses for auto-discovery. + * Useful when you are overloading or extending SimplePie's default classes. + * + * @access public + * @param string $class Name of custom class. + * @link http://php.net/manual/en/keyword.extends.php PHP4 extends documentation + * @link http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.extends PHP5 extends documentation + */ + function set_locator_class($class = 'SimplePie_Locator') + { + if (SimplePie_Misc::is_subclass_of($class, 'SimplePie_Locator')) + { + $this->locator_class = $class; + return true; + } + return false; + } + + /** + * Allows you to change which class SimplePie uses for XML parsing. + * Useful when you are overloading or extending SimplePie's default classes. + * + * @access public + * @param string $class Name of custom class. + * @link http://php.net/manual/en/keyword.extends.php PHP4 extends documentation + * @link http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.extends PHP5 extends documentation + */ + function set_parser_class($class = 'SimplePie_Parser') + { + if (SimplePie_Misc::is_subclass_of($class, 'SimplePie_Parser')) + { + $this->parser_class = $class; + return true; + } + return false; + } + + /** + * Allows you to change which class SimplePie uses for remote file fetching. + * Useful when you are overloading or extending SimplePie's default classes. + * + * @access public + * @param string $class Name of custom class. + * @link http://php.net/manual/en/keyword.extends.php PHP4 extends documentation + * @link http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.extends PHP5 extends documentation + */ + function set_file_class($class = 'SimplePie_File') + { + if (SimplePie_Misc::is_subclass_of($class, 'SimplePie_File')) + { + $this->file_class = $class; + return true; + } + return false; + } + + /** + * Allows you to change which class SimplePie uses for data sanitization. + * Useful when you are overloading or extending SimplePie's default classes. + * + * @access public + * @param string $class Name of custom class. + * @link http://php.net/manual/en/keyword.extends.php PHP4 extends documentation + * @link http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.extends PHP5 extends documentation + */ + function set_sanitize_class($class = 'SimplePie_Sanitize') + { + if (SimplePie_Misc::is_subclass_of($class, 'SimplePie_Sanitize')) + { + $this->sanitize =& new $class; + return true; + } + return false; + } + + /** + * Allows you to change which class SimplePie uses for handling feed items. + * Useful when you are overloading or extending SimplePie's default classes. + * + * @access public + * @param string $class Name of custom class. + * @link http://php.net/manual/en/keyword.extends.php PHP4 extends documentation + * @link http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.extends PHP5 extends documentation + */ + function set_item_class($class = 'SimplePie_Item') + { + if (SimplePie_Misc::is_subclass_of($class, 'SimplePie_Item')) + { + $this->item_class = $class; + return true; + } + return false; + } + + /** + * Allows you to change which class SimplePie uses for handling author data. + * Useful when you are overloading or extending SimplePie's default classes. + * + * @access public + * @param string $class Name of custom class. + * @link http://php.net/manual/en/keyword.extends.php PHP4 extends documentation + * @link http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.extends PHP5 extends documentation + */ + function set_author_class($class = 'SimplePie_Author') + { + if (SimplePie_Misc::is_subclass_of($class, 'SimplePie_Author')) + { + $this->author_class = $class; + return true; + } + return false; + } + + /** + * Allows you to change which class SimplePie uses for handling category data. + * Useful when you are overloading or extending SimplePie's default classes. + * + * @access public + * @param string $class Name of custom class. + * @link http://php.net/manual/en/keyword.extends.php PHP4 extends documentation + * @link http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.extends PHP5 extends documentation + */ + function set_category_class($class = 'SimplePie_Category') + { + if (SimplePie_Misc::is_subclass_of($class, 'SimplePie_Category')) + { + $this->category_class = $class; + return true; + } + return false; + } + + /** + * Allows you to change which class SimplePie uses for feed enclosures. + * Useful when you are overloading or extending SimplePie's default classes. + * + * @access public + * @param string $class Name of custom class. + * @link http://php.net/manual/en/keyword.extends.php PHP4 extends documentation + * @link http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.extends PHP5 extends documentation + */ + function set_enclosure_class($class = 'SimplePie_Enclosure') + { + if (SimplePie_Misc::is_subclass_of($class, 'SimplePie_Enclosure')) + { + $this->enclosure_class = $class; + return true; + } + return false; + } + + /** + * Allows you to change which class SimplePie uses for captions + * Useful when you are overloading or extending SimplePie's default classes. + * + * @access public + * @param string $class Name of custom class. + * @link http://php.net/manual/en/keyword.extends.php PHP4 extends documentation + * @link http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.extends PHP5 extends documentation + */ + function set_caption_class($class = 'SimplePie_Caption') + { + if (SimplePie_Misc::is_subclass_of($class, 'SimplePie_Caption')) + { + $this->caption_class = $class; + return true; + } + return false; + } + + /** + * Allows you to change which class SimplePie uses for + * Useful when you are overloading or extending SimplePie's default classes. + * + * @access public + * @param string $class Name of custom class. + * @link http://php.net/manual/en/keyword.extends.php PHP4 extends documentation + * @link http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.extends PHP5 extends documentation + */ + function set_copyright_class($class = 'SimplePie_Copyright') + { + if (SimplePie_Misc::is_subclass_of($class, 'SimplePie_Copyright')) + { + $this->copyright_class = $class; + return true; + } + return false; + } + + /** + * Allows you to change which class SimplePie uses for + * Useful when you are overloading or extending SimplePie's default classes. + * + * @access public + * @param string $class Name of custom class. + * @link http://php.net/manual/en/keyword.extends.php PHP4 extends documentation + * @link http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.extends PHP5 extends documentation + */ + function set_credit_class($class = 'SimplePie_Credit') + { + if (SimplePie_Misc::is_subclass_of($class, 'SimplePie_Credit')) + { + $this->credit_class = $class; + return true; + } + return false; + } + + /** + * Allows you to change which class SimplePie uses for + * Useful when you are overloading or extending SimplePie's default classes. + * + * @access public + * @param string $class Name of custom class. + * @link http://php.net/manual/en/keyword.extends.php PHP4 extends documentation + * @link http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.extends PHP5 extends documentation + */ + function set_rating_class($class = 'SimplePie_Rating') + { + if (SimplePie_Misc::is_subclass_of($class, 'SimplePie_Rating')) + { + $this->rating_class = $class; + return true; + } + return false; + } + + /** + * Allows you to change which class SimplePie uses for + * Useful when you are overloading or extending SimplePie's default classes. + * + * @access public + * @param string $class Name of custom class. + * @link http://php.net/manual/en/keyword.extends.php PHP4 extends documentation + * @link http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.extends PHP5 extends documentation + */ + function set_restriction_class($class = 'SimplePie_Restriction') + { + if (SimplePie_Misc::is_subclass_of($class, 'SimplePie_Restriction')) + { + $this->restriction_class = $class; + return true; + } + return false; + } + + /** + * Allows you to change which class SimplePie uses for content-type sniffing. + * Useful when you are overloading or extending SimplePie's default classes. + * + * @access public + * @param string $class Name of custom class. + * @link http://php.net/manual/en/keyword.extends.php PHP4 extends documentation + * @link http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.extends PHP5 extends documentation + */ + function set_content_type_sniffer_class($class = 'SimplePie_Content_Type_Sniffer') + { + if (SimplePie_Misc::is_subclass_of($class, 'SimplePie_Content_Type_Sniffer')) + { + $this->content_type_sniffer_class = $class; + return true; + } + return false; + } + + /** + * Allows you to change which class SimplePie uses item sources. + * Useful when you are overloading or extending SimplePie's default classes. + * + * @access public + * @param string $class Name of custom class. + * @link http://php.net/manual/en/keyword.extends.php PHP4 extends documentation + * @link http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.extends PHP5 extends documentation + */ + function set_source_class($class = 'SimplePie_Source') + { + if (SimplePie_Misc::is_subclass_of($class, 'SimplePie_Source')) + { + $this->source_class = $class; + return true; + } + return false; + } + + /** + * Allows you to override the default user agent string. + * + * @access public + * @param string $ua New user agent string. + */ + function set_useragent($ua = SIMPLEPIE_USERAGENT) + { + $this->useragent = (string) $ua; + } + + /** + * Set callback function to create cache filename with + * + * @access public + * @param mixed $function Callback function + */ + function set_cache_name_function($function = 'md5') + { + if (is_callable($function)) + { + $this->cache_name_function = $function; + } + } + + /** + * Set javascript query string parameter + * + * @access public + * @param mixed $get Javascript query string parameter + */ + function set_javascript($get = 'js') + { + if ($get) + { + $this->javascript = (string) $get; + } + else + { + $this->javascript = false; + } + } + + /** + * Set options to make SP as fast as possible. Forgoes a + * substantial amount of data sanitization in favor of speed. + * + * @access public + * @param bool $set Whether to set them or not + */ + function set_stupidly_fast($set = false) + { + if ($set) + { + $this->enable_order_by_date(false); + $this->remove_div(false); + $this->strip_comments(false); + $this->strip_htmltags(false); + $this->strip_attributes(false); + $this->set_image_handler(false); + } + } + + /** + * Set maximum number of feeds to check with autodiscovery + * + * @access public + * @param int $max Maximum number of feeds to check + */ + function set_max_checked_feeds($max = 10) + { + $this->max_checked_feeds = (int) $max; + } + + function remove_div($enable = true) + { + $this->sanitize->remove_div($enable); + } + + function strip_htmltags($tags = '', $encode = null) + { + if ($tags === '') + { + $tags = $this->strip_htmltags; + } + $this->sanitize->strip_htmltags($tags); + if ($encode !== null) + { + $this->sanitize->encode_instead_of_strip($tags); + } + } + + function encode_instead_of_strip($enable = true) + { + $this->sanitize->encode_instead_of_strip($enable); + } + + function strip_attributes($attribs = '') + { + if ($attribs === '') + { + $attribs = $this->strip_attributes; + } + $this->sanitize->strip_attributes($attribs); + } + + function set_output_encoding($encoding = 'UTF-8') + { + $this->sanitize->set_output_encoding($encoding); + } + + function strip_comments($strip = false) + { + $this->sanitize->strip_comments($strip); + } + + /** + * Set element/attribute key/value pairs of HTML attributes + * containing URLs that need to be resolved relative to the feed + * + * @access public + * @since 1.0 + * @param array $element_attribute Element/attribute key/value pairs + */ + function set_url_replacements($element_attribute = array('a' => 'href', 'area' => 'href', 'blockquote' => 'cite', 'del' => 'cite', 'form' => 'action', 'img' => array('longdesc', 'src'), 'input' => 'src', 'ins' => 'cite', 'q' => 'cite')) + { + $this->sanitize->set_url_replacements($element_attribute); + } + + /** + * Set the handler to enable the display of cached favicons. + * + * @access public + * @param str $page Web-accessible path to the handler_favicon.php file. + * @param str $qs The query string that the value should be passed to. + */ + function set_favicon_handler($page = false, $qs = 'i') + { + if ($page != false) + { + $this->favicon_handler = $page . '?' . $qs . '='; + } + else + { + $this->favicon_handler = ''; + } + } + + /** + * Set the handler to enable the display of cached images. + * + * @access public + * @param str $page Web-accessible path to the handler_image.php file. + * @param str $qs The query string that the value should be passed to. + */ + function set_image_handler($page = false, $qs = 'i') + { + if ($page != false) + { + $this->sanitize->set_image_handler($page . '?' . $qs . '='); + } + else + { + $this->image_handler = ''; + } + } + + /** + * Set the limit for items returned per-feed with multifeeds. + * + * @access public + * @param integer $limit The maximum number of items to return. + */ + function set_item_limit($limit = 0) + { + $this->item_limit = (int) $limit; + } + + function init() + { + if ((function_exists('version_compare') && version_compare(PHP_VERSION, '4.3.0', '<')) || !extension_loaded('xml') || !extension_loaded('pcre')) + { + return false; + } + if (isset($_GET[$this->javascript])) + { + if (function_exists('ob_gzhandler')) + { + ob_start('ob_gzhandler'); + } + header('Content-type: text/javascript; charset: UTF-8'); + header('Cache-Control: must-revalidate'); + header('Expires: ' . gmdate('D, d M Y H:i:s', time() + 604800) . ' GMT'); // 7 days + ?> +function embed_odeo(link) { + document.writeln(''); +} + +function embed_quicktime(type, bgcolor, width, height, link, placeholder, loop) { + if (placeholder != '') { + document.writeln(''); + } + else { + document.writeln(''); + } +} + +function embed_flash(bgcolor, width, height, link, loop, type) { + document.writeln(''); +} + +function embed_flv(width, height, link, placeholder, loop, player) { + document.writeln(''); +} + +function embed_wmedia(width, height, link) { + document.writeln(''); +} + sanitize->pass_cache_data($this->cache, $this->cache_location, $this->cache_name_function, $this->cache_class); + $this->sanitize->pass_file_data($this->file_class, $this->timeout, $this->useragent, $this->force_fsockopen); + + if ($this->feed_url !== null || $this->raw_data !== null) + { + $this->data = array(); + $this->multifeed_objects = array(); + $cache = false; + + if ($this->feed_url !== null) + { + $parsed_feed_url = SimplePie_Misc::parse_url($this->feed_url); + // Decide whether to enable caching + if ($this->cache && $parsed_feed_url['scheme'] !== '') + { + $cache = call_user_func(array($this->cache_class, 'create'), $this->cache_location, call_user_func($this->cache_name_function, $this->feed_url), 'spc'); + } + // If it's enabled and we don't want an XML dump, use the cache + if ($cache && !$this->xml_dump) + { + // Load the Cache + $this->data = $cache->load(); + if (!empty($this->data)) + { + // If the cache is for an outdated build of SimplePie + if (!isset($this->data['build']) || $this->data['build'] != SIMPLEPIE_BUILD) + { + $cache->unlink(); + $this->data = array(); + } + // If we've hit a collision just rerun it with caching disabled + elseif (isset($this->data['url']) && $this->data['url'] != $this->feed_url) + { + $cache = false; + $this->data = array(); + } + // If we've got a non feed_url stored (if the page isn't actually a feed, or is a redirect) use that URL. + elseif (isset($this->data['feed_url'])) + { + // If the autodiscovery cache is still valid use it. + if ($cache->mtime() + $this->autodiscovery_cache_duration > time()) + { + // Do not need to do feed autodiscovery yet. + if ($this->data['feed_url'] == $this->data['url']) + { + $cache->unlink(); + $this->data = array(); + } + else + { + $this->set_feed_url($this->data['feed_url']); + return $this->init(); + } + } + } + // Check if the cache has been updated + elseif ($cache->mtime() + $this->cache_duration < time()) + { + // If we have last-modified and/or etag set + if (isset($this->data['headers']['last-modified']) || isset($this->data['headers']['etag'])) + { + $headers = array(); + if (isset($this->data['headers']['last-modified'])) + { + $headers['if-modified-since'] = $this->data['headers']['last-modified']; + } + if (isset($this->data['headers']['etag'])) + { + $headers['if-none-match'] = '"' . $this->data['headers']['etag'] . '"'; + } + $file =& new $this->file_class($this->feed_url, $this->timeout/10, 5, $headers, $this->useragent, $this->force_fsockopen); + if ($file->success) + { + if ($file->status_code == 304) + { + $cache->touch(); + return true; + } + else + { + $headers = $file->headers; + } + } + else + { + unset($file); + } + } + } + // If the cache is still valid, just return true + else + { + return true; + } + } + // If the cache is empty, delete it + else + { + $cache->unlink(); + $this->data = array(); + } + } + // If we don't already have the file (it'll only exist if we've opened it to check if the cache has been modified), open it. + if (!isset($file)) + { + if (is_a($this->file, 'SimplePie_File') && $this->file->url == $this->feed_url) + { + $file =& $this->file; + } + else + { + $file =& new $this->file_class($this->feed_url, $this->timeout, 5, null, $this->useragent, $this->force_fsockopen); + } + } + // If the file connection has an error, set SimplePie::error to that and quit + if (!$file->success) + { + $this->error = $file->error; + if (!empty($this->data)) + { + return true; + } + else + { + return false; + } + } + + if (!$this->force_feed) + { + // Check if the supplied URL is a feed, if it isn't, look for it. + $locate =& new $this->locator_class($file, $this->timeout, $this->useragent, $this->file_class, $this->max_checked_feeds, $this->content_type_sniffer_class); + if (!$locate->is_feed($file)) + { + // We need to unset this so that if SimplePie::set_file() has been called that object is untouched + unset($file); + if ($file = $locate->find($this->autodiscovery)) + { + if ($cache) + { + $this->data = array('url' => $this->feed_url, 'feed_url' => $file->url, 'build' => SIMPLEPIE_BUILD); + if (!$cache->save($this)) + { + trigger_error("$cache->name is not writeable", E_USER_WARNING); + } + $cache = call_user_func(array($this->cache_class, 'create'), $this->cache_location, call_user_func($this->cache_name_function, $file->url), 'spc'); + } + $this->feed_url = $file->url; + } + else + { + $this->error = "A feed could not be found at $this->feed_url"; + SimplePie_Misc::error($this->error, E_USER_NOTICE, __FILE__, __LINE__); + return false; + } + } + $locate = null; + } + + $headers = $file->headers; + $data = $file->body; + $sniffer = new $this->content_type_sniffer_class($file); + $sniffed = $sniffer->get_type(); + } + else + { + $data = $this->raw_data; + } + + // Set up array of possible encodings + $encodings = array(); + + // First check to see if input has been overridden. + if ($this->input_encoding !== false) + { + $encodings[] = $this->input_encoding; + } + + $application_types = array('application/xml', 'application/xml-dtd', 'application/xml-external-parsed-entity'); + $text_types = array('text/xml', 'text/xml-external-parsed-entity'); + + // RFC 3023 (only applies to sniffed content) + if (isset($sniffed)) + { + if (in_array($sniffed, $application_types) || substr($sniffed, 0, 12) === 'application/' && substr($sniffed, -4) === '+xml') + { + if (isset($headers['content-type']) && preg_match('/;\x20?charset=([^;]*)/i', $headers['content-type'], $charset)) + { + $encodings[] = strtoupper($charset[1]); + } + $encodings = array_merge($encodings, SimplePie_Misc::xml_encoding($data)); + $encodings[] = 'UTF-8'; + } + elseif (in_array($sniffed, $text_types) || substr($sniffed, 0, 5) === 'text/' && substr($sniffed, -4) === '+xml') + { + if (isset($headers['content-type']) && preg_match('/;\x20?charset=([^;]*)/i', $headers['content-type'], $charset)) + { + $encodings[] = $charset[1]; + } + $encodings[] = 'US-ASCII'; + } + // Text MIME-type default + elseif (substr($sniffed, 0, 5) === 'text/') + { + $encodings[] = 'US-ASCII'; + } + } + + // Fallback to XML 1.0 Appendix F.1/UTF-8/ISO-8859-1 + $encodings = array_merge($encodings, SimplePie_Misc::xml_encoding($data)); + $encodings[] = 'UTF-8'; + $encodings[] = 'ISO-8859-1'; + + // There's no point in trying an encoding twice + $encodings = array_unique($encodings); + + // If we want the XML, just output that with the most likely encoding and quit + if ($this->xml_dump) + { + header('Content-type: text/xml; charset=' . $encodings[0]); + echo $data; + exit; + } + + // Loop through each possible encoding, till we return something, or run out of possibilities + foreach ($encodings as $encoding) + { + // Change the encoding to UTF-8 (as we always use UTF-8 internally) + if ($utf8_data = SimplePie_Misc::change_encoding($data, $encoding, 'UTF-8')) + { + // Create new parser + $parser =& new $this->parser_class(); + + // If it's parsed fine + if ($parser->parse($utf8_data, 'UTF-8')) + { + $this->data = $parser->get_data(); + if ($this->get_type() & ~SIMPLEPIE_TYPE_NONE) + { + if (isset($headers)) + { + $this->data['headers'] = $headers; + } + $this->data['build'] = SIMPLEPIE_BUILD; + + // Cache the file if caching is enabled + if ($cache && !$cache->save($this)) + { + trigger_error("$cache->name is not writeable", E_USER_WARNING); + } + return true; + } + else + { + $this->error = "A feed could not be found at $this->feed_url"; + SimplePie_Misc::error($this->error, E_USER_NOTICE, __FILE__, __LINE__); + return false; + } + } + } + } + // We have an error, just set SimplePie::error to it and quit + $this->error = sprintf('XML error: %s at line %d, column %d', $parser->get_error_string(), $parser->get_current_line(), $parser->get_current_column()); + SimplePie_Misc::error($this->error, E_USER_NOTICE, __FILE__, __LINE__); + return false; + } + elseif (!empty($this->multifeed_url)) + { + $i = 0; + $success = 0; + $this->multifeed_objects = array(); + foreach ($this->multifeed_url as $url) + { + if (SIMPLEPIE_PHP5) + { + // This keyword needs to defy coding standards for PHP4 compatibility + $this->multifeed_objects[$i] = clone($this); + } + else + { + $this->multifeed_objects[$i] = $this; + } + $this->multifeed_objects[$i]->set_feed_url($url); + $success |= $this->multifeed_objects[$i]->init(); + $i++; + } + return (bool) $success; + } + else + { + return false; + } + } + + /** + * Return the error message for the occured error + * + * @access public + * @return string Error message + */ + function error() + { + return $this->error; + } + + function get_encoding() + { + return $this->sanitize->output_encoding; + } + + function handle_content_type($mime = 'text/html') + { + if (!headers_sent()) + { + $header = "Content-type: $mime;"; + if ($this->get_encoding()) + { + $header .= ' charset=' . $this->get_encoding(); + } + else + { + $header .= ' charset=UTF-8'; + } + header($header); + } + } + + function get_type() + { + if (!isset($this->data['type'])) + { + $this->data['type'] = SIMPLEPIE_TYPE_ALL; + if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'])) + { + $this->data['type'] &= SIMPLEPIE_TYPE_ATOM_10; + } + elseif (isset($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'])) + { + $this->data['type'] &= SIMPLEPIE_TYPE_ATOM_03; + } + elseif (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'])) + { + if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_10]['channel']) + || isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_10]['image']) + || isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_10]['item']) + || isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_10]['textinput'])) + { + $this->data['type'] &= SIMPLEPIE_TYPE_RSS_10; + } + if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_090]['channel']) + || isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_090]['image']) + || isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_090]['item']) + || isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_090]['textinput'])) + { + $this->data['type'] &= SIMPLEPIE_TYPE_RSS_090; + } + } + elseif (isset($this->data['child']['']['rss'])) + { + $this->data['type'] &= SIMPLEPIE_TYPE_RSS_ALL; + if (isset($this->data['child']['']['rss'][0]['attribs']['']['version'])) + { + switch (trim($this->data['child']['']['rss'][0]['attribs']['']['version'])) + { + case '0.91': + $this->data['type'] &= SIMPLEPIE_TYPE_RSS_091; + if (isset($this->data['child']['']['rss'][0]['child']['']['skiphours']['hour'][0]['data'])) + { + switch (trim($this->data['child']['']['rss'][0]['child']['']['skiphours']['hour'][0]['data'])) + { + case '0': + $this->data['type'] &= SIMPLEPIE_TYPE_RSS_091_NETSCAPE; + break; + + case '24': + $this->data['type'] &= SIMPLEPIE_TYPE_RSS_091_USERLAND; + break; + } + } + break; + + case '0.92': + $this->data['type'] &= SIMPLEPIE_TYPE_RSS_092; + break; + + case '0.93': + $this->data['type'] &= SIMPLEPIE_TYPE_RSS_093; + break; + + case '0.94': + $this->data['type'] &= SIMPLEPIE_TYPE_RSS_094; + break; + + case '2.0': + $this->data['type'] &= SIMPLEPIE_TYPE_RSS_20; + break; + } + } + } + else + { + $this->data['type'] = SIMPLEPIE_TYPE_NONE; + } + } + return $this->data['type']; + } + + /** + * Returns the URL for the favicon of the feed's website. + * + * @todo Cache atom:icon + * @access public + * @since 1.0 + */ + function get_favicon() + { + if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'icon')) + { + return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0])); + } + elseif (($url = $this->get_link()) !== null && preg_match('/^http(s)?:\/\//i', $url)) + { + $favicon = SimplePie_Misc::absolutize_url('/favicon.ico', $url); + + if ($this->cache && $this->favicon_handler) + { + $favicon_filename = call_user_func($this->cache_name_function, $favicon); + $cache = call_user_func(array($this->cache_class, 'create'), $this->cache_location, $favicon_filename, 'spi'); + + if ($cache->load()) + { + return $this->sanitize($this->favicon_handler . $favicon_filename, SIMPLEPIE_CONSTRUCT_IRI); + } + else + { + $file =& new $this->file_class($favicon, $this->timeout / 10, 5, array('X-FORWARDED-FOR' => $_SERVER['REMOTE_ADDR']), $this->useragent, $this->force_fsockopen); + + if ($file->success && ($file->status_code == 200 || ($file->status_code > 206 && $file->status_code < 300)) && strlen($file->body) > 0) + { + $sniffer = new $this->content_type_sniffer_class($file); + if (substr($sniffer->get_type(), 0, 6) === 'image/') + { + if ($cache->save(array('headers' => $file->headers, 'body' => $file->body))) + { + return $this->sanitize($this->favicon_handler . $favicon_filename, SIMPLEPIE_CONSTRUCT_IRI); + } + else + { + trigger_error("$cache->name is not writeable", E_USER_WARNING); + return $this->sanitize($favicon, SIMPLEPIE_CONSTRUCT_IRI); + } + } + } + } + } + else + { + return $this->sanitize($favicon, SIMPLEPIE_CONSTRUCT_IRI); + } + } + return false; + } + + /** + * @todo If we have a perm redirect we should return the new URL + * @todo When we make the above change, let's support as well + * @todo Also, |atom:link|@rel=self + */ + function subscribe_url() + { + if ($this->feed_url !== null) + { + return $this->sanitize($this->feed_url, SIMPLEPIE_CONSTRUCT_IRI); + } + else + { + return null; + } + } + + function subscribe_feed() + { + if ($this->feed_url !== null) + { + return $this->sanitize(SimplePie_Misc::fix_protocol($this->feed_url, 2), SIMPLEPIE_CONSTRUCT_IRI); + } + else + { + return null; + } + } + + function subscribe_outlook() + { + if ($this->feed_url !== null) + { + return 'outlook' . $this->sanitize(SimplePie_Misc::fix_protocol($this->feed_url, 2), SIMPLEPIE_CONSTRUCT_IRI); + } + else + { + return null; + } + } + + function subscribe_podcast() + { + if ($this->feed_url !== null) + { + return $this->sanitize(SimplePie_Misc::fix_protocol($this->feed_url, 3), SIMPLEPIE_CONSTRUCT_IRI); + } + else + { + return null; + } + } + + function subscribe_itunes() + { + if ($this->feed_url !== null) + { + return $this->sanitize(SimplePie_Misc::fix_protocol($this->feed_url, 4), SIMPLEPIE_CONSTRUCT_IRI); + } + else + { + return null; + } + } + + /** + * Creates the subscribe_* methods' return data + * + * @access private + * @param string $feed_url String to prefix to the feed URL + * @param string $site_url String to prefix to the site URL (and + * suffix to the feed URL) + * @return mixed URL if feed exists, false otherwise + */ + function subscribe_service($feed_url, $site_url = null) + { + if ($this->subscribe_url()) + { + $return = $this->sanitize($feed_url, SIMPLEPIE_CONSTRUCT_IRI) . rawurlencode($this->feed_url); + if ($site_url !== null && $this->get_link() !== null) + { + $return .= $this->sanitize($site_url, SIMPLEPIE_CONSTRUCT_IRI) . rawurlencode($this->get_link()); + } + return $return; + } + else + { + return null; + } + } + + function subscribe_aol() + { + return $this->subscribe_service('http://feeds.my.aol.com/add.jsp?url='); + } + + function subscribe_bloglines() + { + return urldecode($this->subscribe_service('http://www.bloglines.com/sub/')); + } + + function subscribe_eskobo() + { + return $this->subscribe_service('http://www.eskobo.com/?AddToMyPage='); + } + + function subscribe_feedfeeds() + { + return $this->subscribe_service('http://www.feedfeeds.com/add?feed='); + } + + function subscribe_feedster() + { + return $this->subscribe_service('http://www.feedster.com/myfeedster.php?action=addrss&confirm=no&rssurl='); + } + + function subscribe_google() + { + return $this->subscribe_service('http://fusion.google.com/add?feedurl='); + } + + function subscribe_gritwire() + { + return $this->subscribe_service('http://my.gritwire.com/feeds/addExternalFeed.aspx?FeedUrl='); + } + + function subscribe_msn() + { + return $this->subscribe_service('http://my.msn.com/addtomymsn.armx?id=rss&ut=', '&ru='); + } + + function subscribe_netvibes() + { + return $this->subscribe_service('http://www.netvibes.com/subscribe.php?url='); + } + + function subscribe_newsburst() + { + return $this->subscribe_service('http://www.newsburst.com/Source/?add='); + } + + function subscribe_newsgator() + { + return $this->subscribe_service('http://www.newsgator.com/ngs/subscriber/subext.aspx?url='); + } + + function subscribe_odeo() + { + return $this->subscribe_service('http://www.odeo.com/listen/subscribe?feed='); + } + + function subscribe_podnova() + { + return $this->subscribe_service('http://www.podnova.com/index_your_podcasts.srf?action=add&url='); + } + + function subscribe_rojo() + { + return $this->subscribe_service('http://www.rojo.com/add-subscription?resource='); + } + + function subscribe_yahoo() + { + return $this->subscribe_service('http://add.my.yahoo.com/rss?url='); + } + + function get_feed_tags($namespace, $tag) + { + $type = $this->get_type(); + if ($type & SIMPLEPIE_TYPE_ATOM_10) + { + if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0]['child'][$namespace][$tag])) + { + return $this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0]['child'][$namespace][$tag]; + } + } + if ($type & SIMPLEPIE_TYPE_ATOM_03) + { + if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0]['child'][$namespace][$tag])) + { + return $this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0]['child'][$namespace][$tag]; + } + } + if ($type & SIMPLEPIE_TYPE_RSS_RDF) + { + if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][$namespace][$tag])) + { + return $this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][$namespace][$tag]; + } + } + if ($type & SIMPLEPIE_TYPE_RSS_SYNDICATION) + { + if (isset($this->data['child']['']['rss'][0]['child'][$namespace][$tag])) + { + return $this->data['child']['']['rss'][0]['child'][$namespace][$tag]; + } + } + return null; + } + + function get_channel_tags($namespace, $tag) + { + $type = $this->get_type(); + if ($type & SIMPLEPIE_TYPE_ATOM_ALL) + { + if ($return = $this->get_feed_tags($namespace, $tag)) + { + return $return; + } + } + if ($type & SIMPLEPIE_TYPE_RSS_10) + { + if ($channel = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'channel')) + { + if (isset($channel[0]['child'][$namespace][$tag])) + { + return $channel[0]['child'][$namespace][$tag]; + } + } + } + if ($type & SIMPLEPIE_TYPE_RSS_090) + { + if ($channel = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'channel')) + { + if (isset($channel[0]['child'][$namespace][$tag])) + { + return $channel[0]['child'][$namespace][$tag]; + } + } + } + if ($type & SIMPLEPIE_TYPE_RSS_SYNDICATION) + { + if ($channel = $this->get_feed_tags('', 'channel')) + { + if (isset($channel[0]['child'][$namespace][$tag])) + { + return $channel[0]['child'][$namespace][$tag]; + } + } + } + return null; + } + + function get_image_tags($namespace, $tag) + { + $type = $this->get_type(); + if ($type & SIMPLEPIE_TYPE_RSS_10) + { + if ($image = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'image')) + { + if (isset($image[0]['child'][$namespace][$tag])) + { + return $image[0]['child'][$namespace][$tag]; + } + } + } + if ($type & SIMPLEPIE_TYPE_RSS_090) + { + if ($image = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'image')) + { + if (isset($image[0]['child'][$namespace][$tag])) + { + return $image[0]['child'][$namespace][$tag]; + } + } + } + if ($type & SIMPLEPIE_TYPE_RSS_SYNDICATION) + { + if ($image = $this->get_channel_tags('', 'image')) + { + if (isset($image[0]['child'][$namespace][$tag])) + { + return $image[0]['child'][$namespace][$tag]; + } + } + } + return null; + } + + function get_base($element = array()) + { + if (!($this->get_type() & SIMPLEPIE_TYPE_RSS_SYNDICATION) && !empty($element['xml_base_explicit']) && isset($element['xml_base'])) + { + return $element['xml_base']; + } + elseif ($this->get_link() !== null) + { + return $this->get_link(); + } + else + { + return $this->subscribe_url(); + } + } + + function sanitize($data, $type, $base = '') + { + return $this->sanitize->sanitize($data, $type, $base); + } + + function get_title() + { + if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'title')) + { + return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_10_construct_type($return[0]['attribs']), $this->get_base($return[0])); + } + elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'title')) + { + return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_03_construct_type($return[0]['attribs']), $this->get_base($return[0])); + } + elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'title')) + { + return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0])); + } + elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'title')) + { + return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0])); + } + elseif ($return = $this->get_channel_tags('', 'title')) + { + return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0])); + } + elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_11, 'title')) + { + return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_10, 'title')) + { + return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + else + { + return null; + } + } + + function get_category($key = 0) + { + $categories = $this->get_categories(); + if (isset($categories[$key])) + { + return $categories[$key]; + } + else + { + return null; + } + } + + function get_categories() + { + $categories = array(); + + foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'category') as $category) + { + $term = null; + $scheme = null; + $label = null; + if (isset($category['attribs']['']['term'])) + { + $term = $this->sanitize($category['attribs']['']['term'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($category['attribs']['']['scheme'])) + { + $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($category['attribs']['']['label'])) + { + $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT); + } + $categories[] =& new $this->category_class($term, $scheme, $label); + } + foreach ((array) $this->get_channel_tags('', 'category') as $category) + { + $categories[] =& new $this->category_class($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null); + } + foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_11, 'subject') as $category) + { + $categories[] =& new $this->category_class($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null); + } + foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_10, 'subject') as $category) + { + $categories[] =& new $this->category_class($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null); + } + + if (!empty($categories)) + { + return SimplePie_Misc::array_unique($categories); + } + else + { + return null; + } + } + + function get_author($key = 0) + { + $authors = $this->get_authors(); + if (isset($authors[$key])) + { + return $authors[$key]; + } + else + { + return null; + } + } + + function get_authors() + { + $authors = array(); + foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'author') as $author) + { + $name = null; + $uri = null; + $email = null; + if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'])) + { + $name = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data'])) + { + $uri = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0])); + } + if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'])) + { + $email = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if ($name !== null || $email !== null || $uri !== null) + { + $authors[] =& new $this->author_class($name, $uri, $email); + } + } + if ($author = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'author')) + { + $name = null; + $url = null; + $email = null; + if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'])) + { + $name = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data'])) + { + $url = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0])); + } + if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'])) + { + $email = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if ($name !== null || $email !== null || $url !== null) + { + $authors[] =& new $this->author_class($name, $url, $email); + } + } + foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_11, 'creator') as $author) + { + $authors[] =& new $this->author_class($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null); + } + foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_10, 'creator') as $author) + { + $authors[] =& new $this->author_class($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null); + } + foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'author') as $author) + { + $authors[] =& new $this->author_class($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null); + } + + if (!empty($authors)) + { + return SimplePie_Misc::array_unique($authors); + } + else + { + return null; + } + } + + function get_contributor($key = 0) + { + $contributors = $this->get_contributors(); + if (isset($contributors[$key])) + { + return $contributors[$key]; + } + else + { + return null; + } + } + + function get_contributors() + { + $contributors = array(); + foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'contributor') as $contributor) + { + $name = null; + $uri = null; + $email = null; + if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'])) + { + $name = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data'])) + { + $uri = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0])); + } + if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'])) + { + $email = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if ($name !== null || $email !== null || $uri !== null) + { + $contributors[] =& new $this->author_class($name, $uri, $email); + } + } + foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'contributor') as $contributor) + { + $name = null; + $url = null; + $email = null; + if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'])) + { + $name = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data'])) + { + $url = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0])); + } + if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'])) + { + $email = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if ($name !== null || $email !== null || $url !== null) + { + $contributors[] =& new $this->author_class($name, $url, $email); + } + } + + if (!empty($contributors)) + { + return SimplePie_Misc::array_unique($contributors); + } + else + { + return null; + } + } + + function get_link($key = 0, $rel = 'alternate') + { + $links = $this->get_links($rel); + if (isset($links[$key])) + { + return $links[$key]; + } + else + { + return null; + } + } + + /** + * Added for parity between the parent-level and the item/entry-level. + */ + function get_permalink() + { + return $this->get_link(0); + } + + function get_links($rel = 'alternate') + { + if (!isset($this->data['links'])) + { + $this->data['links'] = array(); + if ($links = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'link')) + { + foreach ($links as $link) + { + if (isset($link['attribs']['']['href'])) + { + $link_rel = (isset($link['attribs']['']['rel'])) ? $link['attribs']['']['rel'] : 'alternate'; + $this->data['links'][$link_rel][] = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link)); + } + } + } + if ($links = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'link')) + { + foreach ($links as $link) + { + if (isset($link['attribs']['']['href'])) + { + $link_rel = (isset($link['attribs']['']['rel'])) ? $link['attribs']['']['rel'] : 'alternate'; + $this->data['links'][$link_rel][] = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link)); + + } + } + } + if ($links = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'link')) + { + $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0])); + } + if ($links = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'link')) + { + $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0])); + } + if ($links = $this->get_channel_tags('', 'link')) + { + $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0])); + } + + $keys = array_keys($this->data['links']); + foreach ($keys as $key) + { + if (SimplePie_Misc::is_isegment_nz_nc($key)) + { + if (isset($this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key])) + { + $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key] = array_merge($this->data['links'][$key], $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key]); + $this->data['links'][$key] =& $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key]; + } + else + { + $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key] =& $this->data['links'][$key]; + } + } + elseif (substr($key, 0, 41) == SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY) + { + $this->data['links'][substr($key, 41)] =& $this->data['links'][$key]; + } + $this->data['links'][$key] = array_unique($this->data['links'][$key]); + } + } + + if (isset($this->data['links'][$rel])) + { + return $this->data['links'][$rel]; + } + else + { + return null; + } + } + + function get_description() + { + if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'subtitle')) + { + return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_10_construct_type($return[0]['attribs']), $this->get_base($return[0])); + } + elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'tagline')) + { + return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_03_construct_type($return[0]['attribs']), $this->get_base($return[0])); + } + elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'description')) + { + return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0])); + } + elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'description')) + { + return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0])); + } + elseif ($return = $this->get_channel_tags('', 'description')) + { + return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0])); + } + elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_11, 'description')) + { + return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_10, 'description')) + { + return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'summary')) + { + return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0])); + } + elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'subtitle')) + { + return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0])); + } + else + { + return null; + } + } + + function get_copyright() + { + if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'rights')) + { + return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_10_construct_type($return[0]['attribs']), $this->get_base($return[0])); + } + elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'copyright')) + { + return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_03_construct_type($return[0]['attribs']), $this->get_base($return[0])); + } + elseif ($return = $this->get_channel_tags('', 'copyright')) + { + return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_11, 'rights')) + { + return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_10, 'rights')) + { + return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + else + { + return null; + } + } + + function get_language() + { + if ($return = $this->get_channel_tags('', 'language')) + { + return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_11, 'language')) + { + return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_10, 'language')) + { + return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + elseif (isset($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0]['xml_lang'])) + { + return $this->sanitize($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0]['xml_lang'], SIMPLEPIE_CONSTRUCT_TEXT); + } + elseif (isset($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0]['xml_lang'])) + { + return $this->sanitize($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0]['xml_lang'], SIMPLEPIE_CONSTRUCT_TEXT); + } + elseif (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['xml_lang'])) + { + return $this->sanitize($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['xml_lang'], SIMPLEPIE_CONSTRUCT_TEXT); + } + elseif (isset($this->data['headers']['content-language'])) + { + return $this->sanitize($this->data['headers']['content-language'], SIMPLEPIE_CONSTRUCT_TEXT); + } + else + { + return null; + } + } + + function get_latitude() + { + if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'lat')) + { + return (float) $return[0]['data']; + } + elseif (($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_GEORSS, 'point')) && preg_match('/^((?:-)?[0-9]+(?:\.[0-9]+)) ((?:-)?[0-9]+(?:\.[0-9]+))$/', $return[0]['data'], $match)) + { + return (float) $match[1]; + } + else + { + return null; + } + } + + function get_longitude() + { + if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'long')) + { + return (float) $return[0]['data']; + } + elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'lon')) + { + return (float) $return[0]['data']; + } + elseif (($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_GEORSS, 'point')) && preg_match('/^((?:-)?[0-9]+(?:\.[0-9]+)) ((?:-)?[0-9]+(?:\.[0-9]+))$/', $return[0]['data'], $match)) + { + return (float) $match[2]; + } + else + { + return null; + } + } + + function get_image_title() + { + if ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'title')) + { + return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'title')) + { + return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + elseif ($return = $this->get_image_tags('', 'title')) + { + return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_DC_11, 'title')) + { + return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_DC_10, 'title')) + { + return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + else + { + return null; + } + } + + function get_image_url() + { + if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'image')) + { + return $this->sanitize($return[0]['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI); + } + elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'logo')) + { + return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0])); + } + elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'icon')) + { + return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0])); + } + elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'url')) + { + return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0])); + } + elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'url')) + { + return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0])); + } + elseif ($return = $this->get_image_tags('', 'url')) + { + return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0])); + } + else + { + return null; + } + } + + function get_image_link() + { + if ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'link')) + { + return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0])); + } + elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'link')) + { + return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0])); + } + elseif ($return = $this->get_image_tags('', 'link')) + { + return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0])); + } + else + { + return null; + } + } + + function get_image_width() + { + if ($return = $this->get_image_tags('', 'width')) + { + return round($return[0]['data']); + } + elseif ($this->get_type() & SIMPLEPIE_TYPE_RSS_SYNDICATION && $this->get_image_tags('', 'url')) + { + return 88.0; + } + else + { + return null; + } + } + + function get_image_height() + { + if ($return = $this->get_image_tags('', 'height')) + { + return round($return[0]['data']); + } + elseif ($this->get_type() & SIMPLEPIE_TYPE_RSS_SYNDICATION && $this->get_image_tags('', 'url')) + { + return 31.0; + } + else + { + return null; + } + } + + function get_item_quantity($max = 0) + { + $qty = count($this->get_items()); + if ($max == 0) + { + return $qty; + } + else + { + return ($qty > $max) ? $max : $qty; + } + } + + function get_item($key = 0) + { + $items = $this->get_items(); + if (isset($items[$key])) + { + return $items[$key]; + } + else + { + return null; + } + } + + function get_items($start = 0, $end = 0) + { + if (!empty($this->multifeed_objects)) + { + return SimplePie::merge_items($this->multifeed_objects, $start, $end, $this->item_limit); + } + elseif (!isset($this->data['items'])) + { + if ($items = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'entry')) + { + $keys = array_keys($items); + foreach ($keys as $key) + { + $this->data['items'][] =& new $this->item_class($this, $items[$key]); + } + } + if ($items = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'entry')) + { + $keys = array_keys($items); + foreach ($keys as $key) + { + $this->data['items'][] =& new $this->item_class($this, $items[$key]); + } + } + if ($items = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'item')) + { + $keys = array_keys($items); + foreach ($keys as $key) + { + $this->data['items'][] =& new $this->item_class($this, $items[$key]); + } + } + if ($items = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'item')) + { + $keys = array_keys($items); + foreach ($keys as $key) + { + $this->data['items'][] =& new $this->item_class($this, $items[$key]); + } + } + if ($items = $this->get_channel_tags('', 'item')) + { + $keys = array_keys($items); + foreach ($keys as $key) + { + $this->data['items'][] =& new $this->item_class($this, $items[$key]); + } + } + } + + if (!empty($this->data['items'])) + { + // If we want to order it by date, check if all items have a date, and then sort it + if ($this->order_by_date) + { + if (!isset($this->data['ordered_items'])) + { + $do_sort = true; + foreach ($this->data['items'] as $item) + { + if (!$item->get_date('U')) + { + $do_sort = false; + break; + } + } + $item = null; + $this->data['ordered_items'] = $this->data['items']; + if ($do_sort) + { + usort($this->data['ordered_items'], array(&$this, 'sort_items')); + } + } + $items = $this->data['ordered_items']; + } + else + { + $items = $this->data['items']; + } + + // Slice the data as desired + if ($end == 0) + { + return array_slice($items, $start); + } + else + { + return array_slice($items, $start, $end); + } + } + else + { + return array(); + } + } + + function sort_items($a, $b) + { + return $a->get_date('U') <= $b->get_date('U'); + } + + function merge_items($urls, $start = 0, $end = 0, $limit = 0) + { + if (is_array($urls) && sizeof($urls) > 0) + { + $items = array(); + foreach ($urls as $arg) + { + if (is_a($arg, 'SimplePie')) + { + $items = array_merge($items, $arg->get_items(0, $limit)); + } + else + { + trigger_error('Arguments must be SimplePie objects', E_USER_WARNING); + } + } + + $do_sort = true; + foreach ($items as $item) + { + if (!$item->get_date('U')) + { + $do_sort = false; + break; + } + } + $item = null; + if ($do_sort) + { + usort($items, array('SimplePie', 'sort_items')); + } + + if ($end == 0) + { + return array_slice($items, $start); + } + else + { + return array_slice($items, $start, $end); + } + } + else + { + trigger_error('Cannot merge zero SimplePie objects', E_USER_WARNING); + return array(); + } + } +} + +class SimplePie_Item +{ + var $feed; + var $data = array(); + + function SimplePie_Item($feed, $data) + { + $this->feed = $feed; + $this->data = $data; + } + + function __toString() + { + return md5(serialize($this->data)); + } + + /** + * Remove items that link back to this before destroying this object + */ + function __destruct() + { + unset($this->feed); + } + + function get_item_tags($namespace, $tag) + { + if (isset($this->data['child'][$namespace][$tag])) + { + return $this->data['child'][$namespace][$tag]; + } + else + { + return null; + } + } + + function get_base($element = array()) + { + return $this->feed->get_base($element); + } + + function sanitize($data, $type, $base = '') + { + return $this->feed->sanitize($data, $type, $base); + } + + function get_feed() + { + return $this->feed; + } + + function get_id($hash = false) + { + if (!$hash) + { + if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'id')) + { + return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'id')) + { + return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + elseif ($return = $this->get_item_tags('', 'guid')) + { + return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'identifier')) + { + return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, 'identifier')) + { + return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + elseif (($return = $this->get_permalink()) !== null) + { + return $return; + } + elseif (($return = $this->get_title()) !== null) + { + return $return; + } + } + if ($this->get_permalink() !== null || $this->get_title() !== null) + { + return md5($this->get_permalink() . $this->get_title()); + } + else + { + return md5(serialize($this->data)); + } + } + + function get_title() + { + if (!isset($this->data['title'])) + { + if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'title')) + { + $this->data['title'] = $this->sanitize($return[0]['data'], SimplePie_Misc::atom_10_construct_type($return[0]['attribs']), $this->get_base($return[0])); + } + elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'title')) + { + $this->data['title'] = $this->sanitize($return[0]['data'], SimplePie_Misc::atom_03_construct_type($return[0]['attribs']), $this->get_base($return[0])); + } + elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'title')) + { + $this->data['title'] = $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0])); + } + elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'title')) + { + $this->data['title'] = $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0])); + } + elseif ($return = $this->get_item_tags('', 'title')) + { + $this->data['title'] = $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0])); + } + elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'title')) + { + $this->data['title'] = $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, 'title')) + { + $this->data['title'] = $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + else + { + $this->data['title'] = null; + } + } + return $this->data['title']; + } + + function get_description($description_only = false) + { + if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'summary')) + { + return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_10_construct_type($return[0]['attribs']), $this->get_base($return[0])); + } + elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'summary')) + { + return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_03_construct_type($return[0]['attribs']), $this->get_base($return[0])); + } + elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'description')) + { + return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0])); + } + elseif ($return = $this->get_item_tags('', 'description')) + { + return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0])); + } + elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'description')) + { + return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, 'description')) + { + return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'summary')) + { + return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0])); + } + elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'subtitle')) + { + return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + elseif (!$description_only) + { + return $this->get_content(true); + } + else + { + return null; + } + } + + function get_content($content_only = false) + { + if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'content')) + { + return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_10_content_construct_type($return[0]['attribs']), $this->get_base($return[0])); + } + elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'content')) + { + return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_03_construct_type($return[0]['attribs']), $this->get_base($return[0])); + } + elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_10_MODULES_CONTENT, 'encoded')) + { + return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0])); + } + elseif (!$content_only) + { + return $this->get_description(true); + } + else + { + return null; + } + } + + function get_category($key = 0) + { + $categories = $this->get_categories(); + if (isset($categories[$key])) + { + return $categories[$key]; + } + else + { + return null; + } + } + + function get_categories() + { + $categories = array(); + + foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'category') as $category) + { + $term = null; + $scheme = null; + $label = null; + if (isset($category['attribs']['']['term'])) + { + $term = $this->sanitize($category['attribs']['']['term'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($category['attribs']['']['scheme'])) + { + $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($category['attribs']['']['label'])) + { + $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT); + } + $categories[] =& new $this->feed->category_class($term, $scheme, $label); + } + foreach ((array) $this->get_item_tags('', 'category') as $category) + { + $categories[] =& new $this->feed->category_class($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null); + } + foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'subject') as $category) + { + $categories[] =& new $this->feed->category_class($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null); + } + foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, 'subject') as $category) + { + $categories[] =& new $this->feed->category_class($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null); + } + + if (!empty($categories)) + { + return SimplePie_Misc::array_unique($categories); + } + else + { + return null; + } + } + + function get_author($key = 0) + { + $authors = $this->get_authors(); + if (isset($authors[$key])) + { + return $authors[$key]; + } + else + { + return null; + } + } + + function get_contributor($key = 0) + { + $contributors = $this->get_contributors(); + if (isset($contributors[$key])) + { + return $contributors[$key]; + } + else + { + return null; + } + } + + function get_contributors() + { + $contributors = array(); + foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'contributor') as $contributor) + { + $name = null; + $uri = null; + $email = null; + if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'])) + { + $name = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data'])) + { + $uri = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0])); + } + if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'])) + { + $email = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if ($name !== null || $email !== null || $uri !== null) + { + $contributors[] =& new $this->feed->author_class($name, $uri, $email); + } + } + foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'contributor') as $contributor) + { + $name = null; + $url = null; + $email = null; + if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'])) + { + $name = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data'])) + { + $url = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0])); + } + if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'])) + { + $email = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if ($name !== null || $email !== null || $url !== null) + { + $contributors[] =& new $this->feed->author_class($name, $url, $email); + } + } + + if (!empty($contributors)) + { + return SimplePie_Misc::array_unique($contributors); + } + else + { + return null; + } + } + + /** + * @todo Atom inheritance (item author, source author, feed author) + */ + function get_authors() + { + $authors = array(); + foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'author') as $author) + { + $name = null; + $uri = null; + $email = null; + if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'])) + { + $name = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data'])) + { + $uri = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0])); + } + if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'])) + { + $email = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if ($name !== null || $email !== null || $uri !== null) + { + $authors[] =& new $this->feed->author_class($name, $uri, $email); + } + } + if ($author = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'author')) + { + $name = null; + $url = null; + $email = null; + if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'])) + { + $name = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data'])) + { + $url = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0])); + } + if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'])) + { + $email = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if ($name !== null || $email !== null || $url !== null) + { + $authors[] =& new $this->feed->author_class($name, $url, $email); + } + } + if ($author = $this->get_item_tags('', 'author')) + { + $authors[] =& new $this->feed->author_class(null, null, $this->sanitize($author[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT)); + } + foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'creator') as $author) + { + $authors[] =& new $this->feed->author_class($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null); + } + foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, 'creator') as $author) + { + $authors[] =& new $this->feed->author_class($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null); + } + foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'author') as $author) + { + $authors[] =& new $this->feed->author_class($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null); + } + + if (!empty($authors)) + { + return SimplePie_Misc::array_unique($authors); + } + elseif (($source = $this->get_source()) && ($authors = $source->get_authors())) + { + return $authors; + } + elseif ($authors = $this->feed->get_authors()) + { + return $authors; + } + else + { + return null; + } + } + + function get_copyright() + { + if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'rights')) + { + return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_10_construct_type($return[0]['attribs']), $this->get_base($return[0])); + } + elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'rights')) + { + return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, 'rights')) + { + return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + else + { + return null; + } + } + + function get_date($date_format = 'j F Y, g:i a') + { + if (!isset($this->data['date'])) + { + if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'published')) + { + $this->data['date']['raw'] = $return[0]['data']; + } + elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'updated')) + { + $this->data['date']['raw'] = $return[0]['data']; + } + elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'issued')) + { + $this->data['date']['raw'] = $return[0]['data']; + } + elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'created')) + { + $this->data['date']['raw'] = $return[0]['data']; + } + elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'modified')) + { + $this->data['date']['raw'] = $return[0]['data']; + } + elseif ($return = $this->get_item_tags('', 'pubDate')) + { + $this->data['date']['raw'] = $return[0]['data']; + } + elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'date')) + { + $this->data['date']['raw'] = $return[0]['data']; + } + elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, 'date')) + { + $this->data['date']['raw'] = $return[0]['data']; + } + + if (!empty($this->data['date']['raw'])) + { + $parser = SimplePie_Parse_Date::get(); + $this->data['date']['parsed'] = $parser->parse($this->data['date']['raw']); + } + else + { + $this->data['date'] = null; + } + } + if ($this->data['date']) + { + $date_format = (string) $date_format; + switch ($date_format) + { + case '': + return $this->sanitize($this->data['date']['raw'], SIMPLEPIE_CONSTRUCT_TEXT); + + case 'U': + return $this->data['date']['parsed']; + + default: + return date($date_format, $this->data['date']['parsed']); + } + } + else + { + return null; + } + } + + function get_local_date($date_format = '%c') + { + if (!$date_format) + { + return $this->sanitize($this->get_date(''), SIMPLEPIE_CONSTRUCT_TEXT); + } + elseif (($date = $this->get_date('U')) !== null) + { + return strftime($date_format, $date); + } + else + { + return null; + } + } + + function get_permalink() + { + $link = $this->get_link(); + $enclosure = $this->get_enclosure(0); + if ($link !== null) + { + return $link; + } + elseif ($enclosure !== null) + { + return $enclosure->get_link(); + } + else + { + return null; + } + } + + function get_link($key = 0, $rel = 'alternate') + { + $links = $this->get_links($rel); + if ($links[$key] !== null) + { + return $links[$key]; + } + else + { + return null; + } + } + + function get_links($rel = 'alternate') + { + if (!isset($this->data['links'])) + { + $this->data['links'] = array(); + foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'link') as $link) + { + if (isset($link['attribs']['']['href'])) + { + $link_rel = (isset($link['attribs']['']['rel'])) ? $link['attribs']['']['rel'] : 'alternate'; + $this->data['links'][$link_rel][] = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link)); + + } + } + foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'link') as $link) + { + if (isset($link['attribs']['']['href'])) + { + $link_rel = (isset($link['attribs']['']['rel'])) ? $link['attribs']['']['rel'] : 'alternate'; + $this->data['links'][$link_rel][] = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link)); + } + } + if ($links = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'link')) + { + $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0])); + } + if ($links = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'link')) + { + $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0])); + } + if ($links = $this->get_item_tags('', 'link')) + { + $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0])); + } + if ($links = $this->get_item_tags('', 'guid')) + { + if (!isset($links[0]['attribs']['']['isPermaLink']) || strtolower(trim($links[0]['attribs']['']['isPermaLink'])) == 'true') + { + $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0])); + } + } + + $keys = array_keys($this->data['links']); + foreach ($keys as $key) + { + if (SimplePie_Misc::is_isegment_nz_nc($key)) + { + if (isset($this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key])) + { + $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key] = array_merge($this->data['links'][$key], $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key]); + $this->data['links'][$key] =& $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key]; + } + else + { + $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key] =& $this->data['links'][$key]; + } + } + elseif (substr($key, 0, 41) == SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY) + { + $this->data['links'][substr($key, 41)] =& $this->data['links'][$key]; + } + $this->data['links'][$key] = array_unique($this->data['links'][$key]); + } + } + if (isset($this->data['links'][$rel])) + { + return $this->data['links'][$rel]; + } + else + { + return null; + } + } + + /** + * @todo Add ability to prefer one type of content over another (in a media group). + */ + function get_enclosure($key = 0, $prefer = null) + { + $enclosures = $this->get_enclosures(); + if (isset($enclosures[$key])) + { + return $enclosures[$key]; + } + else + { + return null; + } + } + + /** + * Grabs all available enclosures (podcasts, etc.) + * + * Supports the RSS tag, as well as Media RSS and iTunes RSS. + * + * At this point, we're pretty much assuming that all enclosures for an item are the same content. Anything else is too complicated to properly support. + * + * @todo Add support for end-user defined sorting of enclosures by type/handler (so we can prefer the faster-loading FLV over MP4). + * @todo If an element exists at a level, but it's value is empty, we should fall back to the value from the parent (if it exists). + */ + function get_enclosures() + { + if (!isset($this->data['enclosures'])) + { + $this->data['enclosures'] = array(); + + // Elements + $captions_parent = null; + $categories_parent = null; + $copyrights_parent = null; + $credits_parent = null; + $description_parent = null; + $duration_parent = null; + $hashes_parent = null; + $keywords_parent = null; + $player_parent = null; + $ratings_parent = null; + $restrictions_parent = null; + $thumbnails_parent = null; + $title_parent = null; + + // Let's do the channel and item-level ones first, and just re-use them if we need to. + $parent = $this->get_feed(); + + // CAPTIONS + if ($captions = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'text')) + { + foreach ($captions as $caption) + { + $caption_type = null; + $caption_lang = null; + $caption_startTime = null; + $caption_endTime = null; + $caption_text = null; + if (isset($caption['attribs']['']['type'])) + { + $caption_type = $this->sanitize($caption['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($caption['attribs']['']['lang'])) + { + $caption_lang = $this->sanitize($caption['attribs']['']['lang'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($caption['attribs']['']['start'])) + { + $caption_startTime = $this->sanitize($caption['attribs']['']['start'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($caption['attribs']['']['end'])) + { + $caption_endTime = $this->sanitize($caption['attribs']['']['end'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($caption['data'])) + { + $caption_text = $this->sanitize($caption['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + $captions_parent[] =& new $this->feed->caption_class($caption_type, $caption_lang, $caption_startTime, $caption_endTime, $caption_text); + } + } + elseif ($captions = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'text')) + { + foreach ($captions as $caption) + { + $caption_type = null; + $caption_lang = null; + $caption_startTime = null; + $caption_endTime = null; + $caption_text = null; + if (isset($caption['attribs']['']['type'])) + { + $caption_type = $this->sanitize($caption['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($caption['attribs']['']['lang'])) + { + $caption_lang = $this->sanitize($caption['attribs']['']['lang'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($caption['attribs']['']['start'])) + { + $caption_startTime = $this->sanitize($caption['attribs']['']['start'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($caption['attribs']['']['end'])) + { + $caption_endTime = $this->sanitize($caption['attribs']['']['end'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($caption['data'])) + { + $caption_text = $this->sanitize($caption['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + $captions_parent[] =& new $this->feed->caption_class($caption_type, $caption_lang, $caption_startTime, $caption_endTime, $caption_text); + } + } + if (is_array($captions_parent)) + { + $captions_parent = array_values(SimplePie_Misc::array_unique($captions_parent)); + } + + // CATEGORIES + foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'category') as $category) + { + $term = null; + $scheme = null; + $label = null; + if (isset($category['data'])) + { + $term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($category['attribs']['']['scheme'])) + { + $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT); + } + else + { + $scheme = 'http://search.yahoo.com/mrss/category_schema'; + } + if (isset($category['attribs']['']['label'])) + { + $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT); + } + $categories_parent[] =& new $this->feed->category_class($term, $scheme, $label); + } + foreach ((array) $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'category') as $category) + { + $term = null; + $scheme = null; + $label = null; + if (isset($category['data'])) + { + $term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($category['attribs']['']['scheme'])) + { + $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT); + } + else + { + $scheme = 'http://search.yahoo.com/mrss/category_schema'; + } + if (isset($category['attribs']['']['label'])) + { + $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT); + } + $categories_parent[] =& new $this->feed->category_class($term, $scheme, $label); + } + foreach ((array) $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'category') as $category) + { + $term = null; + $scheme = 'http://www.itunes.com/dtds/podcast-1.0.dtd'; + $label = null; + if (isset($category['attribs']['']['text'])) + { + $label = $this->sanitize($category['attribs']['']['text'], SIMPLEPIE_CONSTRUCT_TEXT); + } + $categories_parent[] =& new $this->feed->category_class($term, $scheme, $label); + + if (isset($category['child'][SIMPLEPIE_NAMESPACE_ITUNES]['category'])) + { + foreach ((array) $category['child'][SIMPLEPIE_NAMESPACE_ITUNES]['category'] as $subcategory) + { + if (isset($subcategory['attribs']['']['text'])) + { + $label = $this->sanitize($subcategory['attribs']['']['text'], SIMPLEPIE_CONSTRUCT_TEXT); + } + $categories_parent[] =& new $this->feed->category_class($term, $scheme, $label); + } + } + } + if (is_array($categories_parent)) + { + $categories_parent = array_values(SimplePie_Misc::array_unique($categories_parent)); + } + + // COPYRIGHT + if ($copyright = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'copyright')) + { + $copyright_url = null; + $copyright_label = null; + if (isset($copyright[0]['attribs']['']['url'])) + { + $copyright_url = $this->sanitize($copyright[0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($copyright[0]['data'])) + { + $copyright_label = $this->sanitize($copyright[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + $copyrights_parent =& new $this->feed->copyright_class($copyright_url, $copyright_label); + } + elseif ($copyright = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'copyright')) + { + $copyright_url = null; + $copyright_label = null; + if (isset($copyright[0]['attribs']['']['url'])) + { + $copyright_url = $this->sanitize($copyright[0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($copyright[0]['data'])) + { + $copyright_label = $this->sanitize($copyright[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + $copyrights_parent =& new $this->feed->copyright_class($copyright_url, $copyright_label); + } + + // CREDITS + if ($credits = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'credit')) + { + foreach ($credits as $credit) + { + $credit_role = null; + $credit_scheme = null; + $credit_name = null; + if (isset($credit['attribs']['']['role'])) + { + $credit_role = $this->sanitize($credit['attribs']['']['role'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($credit['attribs']['']['scheme'])) + { + $credit_scheme = $this->sanitize($credit['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT); + } + else + { + $credit_scheme = 'urn:ebu'; + } + if (isset($credit['data'])) + { + $credit_name = $this->sanitize($credit['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + $credits_parent[] =& new $this->feed->credit_class($credit_role, $credit_scheme, $credit_name); + } + } + elseif ($credits = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'credit')) + { + foreach ($credits as $credit) + { + $credit_role = null; + $credit_scheme = null; + $credit_name = null; + if (isset($credit['attribs']['']['role'])) + { + $credit_role = $this->sanitize($credit['attribs']['']['role'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($credit['attribs']['']['scheme'])) + { + $credit_scheme = $this->sanitize($credit['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT); + } + else + { + $credit_scheme = 'urn:ebu'; + } + if (isset($credit['data'])) + { + $credit_name = $this->sanitize($credit['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + $credits_parent[] =& new $this->feed->credit_class($credit_role, $credit_scheme, $credit_name); + } + } + if (is_array($credits_parent)) + { + $credits_parent = array_values(SimplePie_Misc::array_unique($credits_parent)); + } + + // DESCRIPTION + if ($description_parent = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'description')) + { + if (isset($description_parent[0]['data'])) + { + $description_parent = $this->sanitize($description_parent[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + } + elseif ($description_parent = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'description')) + { + if (isset($description_parent[0]['data'])) + { + $description_parent = $this->sanitize($description_parent[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + } + + // DURATION + if ($duration_parent = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'duration')) + { + $seconds = null; + $minutes = null; + $hours = null; + if (isset($duration_parent[0]['data'])) + { + $temp = explode(':', $this->sanitize($duration_parent[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT)); + if (sizeof($temp) > 0) + { + (int) $seconds = array_pop($temp); + } + if (sizeof($temp) > 0) + { + (int) $minutes = array_pop($temp); + $seconds += $minutes * 60; + } + if (sizeof($temp) > 0) + { + (int) $hours = array_pop($temp); + $seconds += $hours * 3600; + } + unset($temp); + $duration_parent = $seconds; + } + } + + // HASHES + if ($hashes_iterator = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'hash')) + { + foreach ($hashes_iterator as $hash) + { + $value = null; + $algo = null; + if (isset($hash['data'])) + { + $value = $this->sanitize($hash['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($hash['attribs']['']['algo'])) + { + $algo = $this->sanitize($hash['attribs']['']['algo'], SIMPLEPIE_CONSTRUCT_TEXT); + } + else + { + $algo = 'md5'; + } + $hashes_parent[] = $algo.':'.$value; + } + } + elseif ($hashes_iterator = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'hash')) + { + foreach ($hashes_iterator as $hash) + { + $value = null; + $algo = null; + if (isset($hash['data'])) + { + $value = $this->sanitize($hash['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($hash['attribs']['']['algo'])) + { + $algo = $this->sanitize($hash['attribs']['']['algo'], SIMPLEPIE_CONSTRUCT_TEXT); + } + else + { + $algo = 'md5'; + } + $hashes_parent[] = $algo.':'.$value; + } + } + if (is_array($hashes_parent)) + { + $hashes_parent = array_values(SimplePie_Misc::array_unique($hashes_parent)); + } + + // KEYWORDS + if ($keywords = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'keywords')) + { + if (isset($keywords[0]['data'])) + { + $temp = explode(',', $this->sanitize($keywords[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT)); + foreach ($temp as $word) + { + $keywords_parent[] = trim($word); + } + } + unset($temp); + } + elseif ($keywords = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'keywords')) + { + if (isset($keywords[0]['data'])) + { + $temp = explode(',', $this->sanitize($keywords[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT)); + foreach ($temp as $word) + { + $keywords_parent[] = trim($word); + } + } + unset($temp); + } + elseif ($keywords = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'keywords')) + { + if (isset($keywords[0]['data'])) + { + $temp = explode(',', $this->sanitize($keywords[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT)); + foreach ($temp as $word) + { + $keywords_parent[] = trim($word); + } + } + unset($temp); + } + elseif ($keywords = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'keywords')) + { + if (isset($keywords[0]['data'])) + { + $temp = explode(',', $this->sanitize($keywords[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT)); + foreach ($temp as $word) + { + $keywords_parent[] = trim($word); + } + } + unset($temp); + } + if (is_array($keywords_parent)) + { + $keywords_parent = array_values(SimplePie_Misc::array_unique($keywords_parent)); + } + + // PLAYER + if ($player_parent = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'player')) + { + if (isset($player_parent[0]['attribs']['']['url'])) + { + $player_parent = $this->sanitize($player_parent[0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI); + } + } + elseif ($player_parent = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'player')) + { + if (isset($player_parent[0]['attribs']['']['url'])) + { + $player_parent = $this->sanitize($player_parent[0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI); + } + } + + // RATINGS + if ($ratings = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'rating')) + { + foreach ($ratings as $rating) + { + $rating_scheme = null; + $rating_value = null; + if (isset($rating['attribs']['']['scheme'])) + { + $rating_scheme = $this->sanitize($rating['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT); + } + else + { + $rating_scheme = 'urn:simple'; + } + if (isset($rating['data'])) + { + $rating_value = $this->sanitize($rating['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + $ratings_parent[] =& new $this->feed->rating_class($rating_scheme, $rating_value); + } + } + elseif ($ratings = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'explicit')) + { + foreach ($ratings as $rating) + { + $rating_scheme = 'urn:itunes'; + $rating_value = null; + if (isset($rating['data'])) + { + $rating_value = $this->sanitize($rating['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + $ratings_parent[] =& new $this->feed->rating_class($rating_scheme, $rating_value); + } + } + elseif ($ratings = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'rating')) + { + foreach ($ratings as $rating) + { + $rating_scheme = null; + $rating_value = null; + if (isset($rating['attribs']['']['scheme'])) + { + $rating_scheme = $this->sanitize($rating['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT); + } + else + { + $rating_scheme = 'urn:simple'; + } + if (isset($rating['data'])) + { + $rating_value = $this->sanitize($rating['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + $ratings_parent[] =& new $this->feed->rating_class($rating_scheme, $rating_value); + } + } + elseif ($ratings = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'explicit')) + { + foreach ($ratings as $rating) + { + $rating_scheme = 'urn:itunes'; + $rating_value = null; + if (isset($rating['data'])) + { + $rating_value = $this->sanitize($rating['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + $ratings_parent[] =& new $this->feed->rating_class($rating_scheme, $rating_value); + } + } + if (is_array($ratings_parent)) + { + $ratings_parent = array_values(SimplePie_Misc::array_unique($ratings_parent)); + } + + // RESTRICTIONS + if ($restrictions = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'restriction')) + { + foreach ($restrictions as $restriction) + { + $restriction_relationship = null; + $restriction_type = null; + $restriction_value = null; + if (isset($restriction['attribs']['']['relationship'])) + { + $restriction_relationship = $this->sanitize($restriction['attribs']['']['relationship'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($restriction['attribs']['']['type'])) + { + $restriction_type = $this->sanitize($restriction['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($restriction['data'])) + { + $restriction_value = $this->sanitize($restriction['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + $restrictions_parent[] =& new $this->feed->restriction_class($restriction_relationship, $restriction_type, $restriction_value); + } + } + elseif ($restrictions = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'block')) + { + foreach ($restrictions as $restriction) + { + $restriction_relationship = 'allow'; + $restriction_type = null; + $restriction_value = 'itunes'; + if (isset($restriction['data']) && strtolower($restriction['data']) == 'yes') + { + $restriction_relationship = 'deny'; + } + $restrictions_parent[] =& new $this->feed->restriction_class($restriction_relationship, $restriction_type, $restriction_value); + } + } + elseif ($restrictions = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'restriction')) + { + foreach ($restrictions as $restriction) + { + $restriction_relationship = null; + $restriction_type = null; + $restriction_value = null; + if (isset($restriction['attribs']['']['relationship'])) + { + $restriction_relationship = $this->sanitize($restriction['attribs']['']['relationship'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($restriction['attribs']['']['type'])) + { + $restriction_type = $this->sanitize($restriction['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($restriction['data'])) + { + $restriction_value = $this->sanitize($restriction['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + $restrictions_parent[] =& new $this->feed->restriction_class($restriction_relationship, $restriction_type, $restriction_value); + } + } + elseif ($restrictions = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'block')) + { + foreach ($restrictions as $restriction) + { + $restriction_relationship = 'allow'; + $restriction_type = null; + $restriction_value = 'itunes'; + if (isset($restriction['data']) && strtolower($restriction['data']) == 'yes') + { + $restriction_relationship = 'deny'; + } + $restrictions_parent[] =& new $this->feed->restriction_class($restriction_relationship, $restriction_type, $restriction_value); + } + } + if (is_array($restrictions_parent)) + { + $restrictions_parent = array_values(SimplePie_Misc::array_unique($restrictions_parent)); + } + + // THUMBNAILS + if ($thumbnails = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'thumbnail')) + { + foreach ($thumbnails as $thumbnail) + { + if (isset($thumbnail['attribs']['']['url'])) + { + $thumbnails_parent[] = $this->sanitize($thumbnail['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI); + } + } + } + elseif ($thumbnails = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'thumbnail')) + { + foreach ($thumbnails as $thumbnail) + { + if (isset($thumbnail['attribs']['']['url'])) + { + $thumbnails_parent[] = $this->sanitize($thumbnail['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI); + } + } + } + + // TITLES + if ($title_parent = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'title')) + { + if (isset($title_parent[0]['data'])) + { + $title_parent = $this->sanitize($title_parent[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + } + elseif ($title_parent = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'title')) + { + if (isset($title_parent[0]['data'])) + { + $title_parent = $this->sanitize($title_parent[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + } + + // Clear the memory + unset($parent); + + // Attributes + $bitrate = null; + $channels = null; + $duration = null; + $expression = null; + $framerate = null; + $height = null; + $javascript = null; + $lang = null; + $length = null; + $medium = null; + $samplingrate = null; + $type = null; + $url = null; + $width = null; + + // Elements + $captions = null; + $categories = null; + $copyrights = null; + $credits = null; + $description = null; + $hashes = null; + $keywords = null; + $player = null; + $ratings = null; + $restrictions = null; + $thumbnails = null; + $title = null; + + // If we have media:group tags, loop through them. + foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'group') as $group) + { + // If we have media:content tags, loop through them. + foreach ((array) $group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['content'] as $content) + { + if (isset($content['attribs']['']['url'])) + { + // Attributes + $bitrate = null; + $channels = null; + $duration = null; + $expression = null; + $framerate = null; + $height = null; + $javascript = null; + $lang = null; + $length = null; + $medium = null; + $samplingrate = null; + $type = null; + $url = null; + $width = null; + + // Elements + $captions = null; + $categories = null; + $copyrights = null; + $credits = null; + $description = null; + $hashes = null; + $keywords = null; + $player = null; + $ratings = null; + $restrictions = null; + $thumbnails = null; + $title = null; + + // Start checking the attributes of media:content + if (isset($content['attribs']['']['bitrate'])) + { + $bitrate = $this->sanitize($content['attribs']['']['bitrate'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($content['attribs']['']['channels'])) + { + $channels = $this->sanitize($content['attribs']['']['channels'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($content['attribs']['']['duration'])) + { + $duration = $this->sanitize($content['attribs']['']['duration'], SIMPLEPIE_CONSTRUCT_TEXT); + } + else + { + $duration = $duration_parent; + } + if (isset($content['attribs']['']['expression'])) + { + $expression = $this->sanitize($content['attribs']['']['expression'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($content['attribs']['']['framerate'])) + { + $framerate = $this->sanitize($content['attribs']['']['framerate'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($content['attribs']['']['height'])) + { + $height = $this->sanitize($content['attribs']['']['height'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($content['attribs']['']['lang'])) + { + $lang = $this->sanitize($content['attribs']['']['lang'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($content['attribs']['']['fileSize'])) + { + $length = ceil($content['attribs']['']['fileSize']); + } + if (isset($content['attribs']['']['medium'])) + { + $medium = $this->sanitize($content['attribs']['']['medium'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($content['attribs']['']['samplingrate'])) + { + $samplingrate = $this->sanitize($content['attribs']['']['samplingrate'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($content['attribs']['']['type'])) + { + $type = $this->sanitize($content['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($content['attribs']['']['width'])) + { + $width = $this->sanitize($content['attribs']['']['width'], SIMPLEPIE_CONSTRUCT_TEXT); + } + $url = $this->sanitize($content['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI); + + // Checking the other optional media: elements. Priority: media:content, media:group, item, channel + + // CAPTIONS + if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['text'])) + { + foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['text'] as $caption) + { + $caption_type = null; + $caption_lang = null; + $caption_startTime = null; + $caption_endTime = null; + $caption_text = null; + if (isset($caption['attribs']['']['type'])) + { + $caption_type = $this->sanitize($caption['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($caption['attribs']['']['lang'])) + { + $caption_lang = $this->sanitize($caption['attribs']['']['lang'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($caption['attribs']['']['start'])) + { + $caption_startTime = $this->sanitize($caption['attribs']['']['start'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($caption['attribs']['']['end'])) + { + $caption_endTime = $this->sanitize($caption['attribs']['']['end'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($caption['data'])) + { + $caption_text = $this->sanitize($caption['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + $captions[] =& new $this->feed->caption_class($caption_type, $caption_lang, $caption_startTime, $caption_endTime, $caption_text); + } + if (is_array($captions)) + { + $captions = array_values(SimplePie_Misc::array_unique($captions)); + } + } + elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['text'])) + { + foreach ($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['text'] as $caption) + { + $caption_type = null; + $caption_lang = null; + $caption_startTime = null; + $caption_endTime = null; + $caption_text = null; + if (isset($caption['attribs']['']['type'])) + { + $caption_type = $this->sanitize($caption['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($caption['attribs']['']['lang'])) + { + $caption_lang = $this->sanitize($caption['attribs']['']['lang'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($caption['attribs']['']['start'])) + { + $caption_startTime = $this->sanitize($caption['attribs']['']['start'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($caption['attribs']['']['end'])) + { + $caption_endTime = $this->sanitize($caption['attribs']['']['end'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($caption['data'])) + { + $caption_text = $this->sanitize($caption['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + $captions[] =& new $this->feed->caption_class($caption_type, $caption_lang, $caption_startTime, $caption_endTime, $caption_text); + } + if (is_array($captions)) + { + $captions = array_values(SimplePie_Misc::array_unique($captions)); + } + } + else + { + $captions = $captions_parent; + } + + // CATEGORIES + if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['category'])) + { + foreach ((array) $content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['category'] as $category) + { + $term = null; + $scheme = null; + $label = null; + if (isset($category['data'])) + { + $term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($category['attribs']['']['scheme'])) + { + $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT); + } + else + { + $scheme = 'http://search.yahoo.com/mrss/category_schema'; + } + if (isset($category['attribs']['']['label'])) + { + $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT); + } + $categories[] =& new $this->feed->category_class($term, $scheme, $label); + } + } + if (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['category'])) + { + foreach ((array) $group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['category'] as $category) + { + $term = null; + $scheme = null; + $label = null; + if (isset($category['data'])) + { + $term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($category['attribs']['']['scheme'])) + { + $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT); + } + else + { + $scheme = 'http://search.yahoo.com/mrss/category_schema'; + } + if (isset($category['attribs']['']['label'])) + { + $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT); + } + $categories[] =& new $this->feed->category_class($term, $scheme, $label); + } + } + if (is_array($categories) && is_array($categories_parent)) + { + $categories = array_values(SimplePie_Misc::array_unique(array_merge($categories, $categories_parent))); + } + elseif (is_array($categories)) + { + $categories = array_values(SimplePie_Misc::array_unique($categories)); + } + elseif (is_array($categories_parent)) + { + $categories = array_values(SimplePie_Misc::array_unique($categories_parent)); + } + + // COPYRIGHTS + if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'])) + { + $copyright_url = null; + $copyright_label = null; + if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['attribs']['']['url'])) + { + $copyright_url = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['data'])) + { + $copyright_label = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + $copyrights =& new $this->feed->copyright_class($copyright_url, $copyright_label); + } + elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'])) + { + $copyright_url = null; + $copyright_label = null; + if (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['attribs']['']['url'])) + { + $copyright_url = $this->sanitize($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['data'])) + { + $copyright_label = $this->sanitize($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + $copyrights =& new $this->feed->copyright_class($copyright_url, $copyright_label); + } + else + { + $copyrights = $copyrights_parent; + } + + // CREDITS + if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['credit'])) + { + foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['credit'] as $credit) + { + $credit_role = null; + $credit_scheme = null; + $credit_name = null; + if (isset($credit['attribs']['']['role'])) + { + $credit_role = $this->sanitize($credit['attribs']['']['role'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($credit['attribs']['']['scheme'])) + { + $credit_scheme = $this->sanitize($credit['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT); + } + else + { + $credit_scheme = 'urn:ebu'; + } + if (isset($credit['data'])) + { + $credit_name = $this->sanitize($credit['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + $credits[] =& new $this->feed->credit_class($credit_role, $credit_scheme, $credit_name); + } + if (is_array($credits)) + { + $credits = array_values(SimplePie_Misc::array_unique($credits)); + } + } + elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['credit'])) + { + foreach ($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['credit'] as $credit) + { + $credit_role = null; + $credit_scheme = null; + $credit_name = null; + if (isset($credit['attribs']['']['role'])) + { + $credit_role = $this->sanitize($credit['attribs']['']['role'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($credit['attribs']['']['scheme'])) + { + $credit_scheme = $this->sanitize($credit['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT); + } + else + { + $credit_scheme = 'urn:ebu'; + } + if (isset($credit['data'])) + { + $credit_name = $this->sanitize($credit['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + $credits[] =& new $this->feed->credit_class($credit_role, $credit_scheme, $credit_name); + } + if (is_array($credits)) + { + $credits = array_values(SimplePie_Misc::array_unique($credits)); + } + } + else + { + $credits = $credits_parent; + } + + // DESCRIPTION + if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['description'])) + { + $description = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['description'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['description'])) + { + $description = $this->sanitize($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['description'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + else + { + $description = $description_parent; + } + + // HASHES + if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['hash'])) + { + foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['hash'] as $hash) + { + $value = null; + $algo = null; + if (isset($hash['data'])) + { + $value = $this->sanitize($hash['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($hash['attribs']['']['algo'])) + { + $algo = $this->sanitize($hash['attribs']['']['algo'], SIMPLEPIE_CONSTRUCT_TEXT); + } + else + { + $algo = 'md5'; + } + $hashes[] = $algo.':'.$value; + } + if (is_array($hashes)) + { + $hashes = array_values(SimplePie_Misc::array_unique($hashes)); + } + } + elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['hash'])) + { + foreach ($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['hash'] as $hash) + { + $value = null; + $algo = null; + if (isset($hash['data'])) + { + $value = $this->sanitize($hash['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($hash['attribs']['']['algo'])) + { + $algo = $this->sanitize($hash['attribs']['']['algo'], SIMPLEPIE_CONSTRUCT_TEXT); + } + else + { + $algo = 'md5'; + } + $hashes[] = $algo.':'.$value; + } + if (is_array($hashes)) + { + $hashes = array_values(SimplePie_Misc::array_unique($hashes)); + } + } + else + { + $hashes = $hashes_parent; + } + + // KEYWORDS + if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords'])) + { + if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords'][0]['data'])) + { + $temp = explode(',', $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT)); + foreach ($temp as $word) + { + $keywords[] = trim($word); + } + unset($temp); + } + if (is_array($keywords)) + { + $keywords = array_values(SimplePie_Misc::array_unique($keywords)); + } + } + elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords'])) + { + if (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords'][0]['data'])) + { + $temp = explode(',', $this->sanitize($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT)); + foreach ($temp as $word) + { + $keywords[] = trim($word); + } + unset($temp); + } + if (is_array($keywords)) + { + $keywords = array_values(SimplePie_Misc::array_unique($keywords)); + } + } + else + { + $keywords = $keywords_parent; + } + + // PLAYER + if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['player'])) + { + $player = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['player'][0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI); + } + elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['player'])) + { + $player = $this->sanitize($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['player'][0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI); + } + else + { + $player = $player_parent; + } + + // RATINGS + if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['rating'])) + { + foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['rating'] as $rating) + { + $rating_scheme = null; + $rating_value = null; + if (isset($rating['attribs']['']['scheme'])) + { + $rating_scheme = $this->sanitize($rating['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT); + } + else + { + $rating_scheme = 'urn:simple'; + } + if (isset($rating['data'])) + { + $rating_value = $this->sanitize($rating['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + $ratings[] =& new $this->feed->rating_class($rating_scheme, $rating_value); + } + if (is_array($ratings)) + { + $ratings = array_values(SimplePie_Misc::array_unique($ratings)); + } + } + elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['rating'])) + { + foreach ($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['rating'] as $rating) + { + $rating_scheme = null; + $rating_value = null; + if (isset($rating['attribs']['']['scheme'])) + { + $rating_scheme = $this->sanitize($rating['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT); + } + else + { + $rating_scheme = 'urn:simple'; + } + if (isset($rating['data'])) + { + $rating_value = $this->sanitize($rating['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + $ratings[] =& new $this->feed->rating_class($rating_scheme, $rating_value); + } + if (is_array($ratings)) + { + $ratings = array_values(SimplePie_Misc::array_unique($ratings)); + } + } + else + { + $ratings = $ratings_parent; + } + + // RESTRICTIONS + if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['restriction'])) + { + foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['restriction'] as $restriction) + { + $restriction_relationship = null; + $restriction_type = null; + $restriction_value = null; + if (isset($restriction['attribs']['']['relationship'])) + { + $restriction_relationship = $this->sanitize($restriction['attribs']['']['relationship'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($restriction['attribs']['']['type'])) + { + $restriction_type = $this->sanitize($restriction['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($restriction['data'])) + { + $restriction_value = $this->sanitize($restriction['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + $restrictions[] =& new $this->feed->restriction_class($restriction_relationship, $restriction_type, $restriction_value); + } + if (is_array($restrictions)) + { + $restrictions = array_values(SimplePie_Misc::array_unique($restrictions)); + } + } + elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['restriction'])) + { + foreach ($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['restriction'] as $restriction) + { + $restriction_relationship = null; + $restriction_type = null; + $restriction_value = null; + if (isset($restriction['attribs']['']['relationship'])) + { + $restriction_relationship = $this->sanitize($restriction['attribs']['']['relationship'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($restriction['attribs']['']['type'])) + { + $restriction_type = $this->sanitize($restriction['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($restriction['data'])) + { + $restriction_value = $this->sanitize($restriction['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + $restrictions[] =& new $this->feed->restriction_class($restriction_relationship, $restriction_type, $restriction_value); + } + if (is_array($restrictions)) + { + $restrictions = array_values(SimplePie_Misc::array_unique($restrictions)); + } + } + else + { + $restrictions = $restrictions_parent; + } + + // THUMBNAILS + if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['thumbnail'])) + { + foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['thumbnail'] as $thumbnail) + { + $thumbnails[] = $this->sanitize($thumbnail['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI); + } + if (is_array($thumbnails)) + { + $thumbnails = array_values(SimplePie_Misc::array_unique($thumbnails)); + } + } + elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['thumbnail'])) + { + foreach ($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['thumbnail'] as $thumbnail) + { + $thumbnails[] = $this->sanitize($thumbnail['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI); + } + if (is_array($thumbnails)) + { + $thumbnails = array_values(SimplePie_Misc::array_unique($thumbnails)); + } + } + else + { + $thumbnails = $thumbnails_parent; + } + + // TITLES + if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['title'])) + { + $title = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['title'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['title'])) + { + $title = $this->sanitize($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['title'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + else + { + $title = $title_parent; + } + + $this->data['enclosures'][] =& new $this->feed->enclosure_class($url, $type, $length, $this->feed->javascript, $bitrate, $captions, $categories, $channels, $copyrights, $credits, $description, $duration, $expression, $framerate, $hashes, $height, $keywords, $lang, $medium, $player, $ratings, $restrictions, $samplingrate, $thumbnails, $title, $width); + } + } + } + + // If we have standalone media:content tags, loop through them. + if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['content'])) + { + foreach ((array) $this->data['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['content'] as $content) + { + if (isset($content['attribs']['']['url'])) + { + // Attributes + $bitrate = null; + $channels = null; + $duration = null; + $expression = null; + $framerate = null; + $height = null; + $javascript = null; + $lang = null; + $length = null; + $medium = null; + $samplingrate = null; + $type = null; + $url = null; + $width = null; + + // Elements + $captions = null; + $categories = null; + $copyrights = null; + $credits = null; + $description = null; + $hashes = null; + $keywords = null; + $player = null; + $ratings = null; + $restrictions = null; + $thumbnails = null; + $title = null; + + // Start checking the attributes of media:content + if (isset($content['attribs']['']['bitrate'])) + { + $bitrate = $this->sanitize($content['attribs']['']['bitrate'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($content['attribs']['']['channels'])) + { + $channels = $this->sanitize($content['attribs']['']['channels'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($content['attribs']['']['duration'])) + { + $duration = $this->sanitize($content['attribs']['']['duration'], SIMPLEPIE_CONSTRUCT_TEXT); + } + else + { + $duration = $duration_parent; + } + if (isset($content['attribs']['']['expression'])) + { + $expression = $this->sanitize($content['attribs']['']['expression'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($content['attribs']['']['framerate'])) + { + $framerate = $this->sanitize($content['attribs']['']['framerate'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($content['attribs']['']['height'])) + { + $height = $this->sanitize($content['attribs']['']['height'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($content['attribs']['']['lang'])) + { + $lang = $this->sanitize($content['attribs']['']['lang'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($content['attribs']['']['fileSize'])) + { + $length = ceil($content['attribs']['']['fileSize']); + } + if (isset($content['attribs']['']['medium'])) + { + $medium = $this->sanitize($content['attribs']['']['medium'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($content['attribs']['']['samplingrate'])) + { + $samplingrate = $this->sanitize($content['attribs']['']['samplingrate'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($content['attribs']['']['type'])) + { + $type = $this->sanitize($content['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($content['attribs']['']['width'])) + { + $width = $this->sanitize($content['attribs']['']['width'], SIMPLEPIE_CONSTRUCT_TEXT); + } + $url = $this->sanitize($content['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI); + + // Checking the other optional media: elements. Priority: media:content, media:group, item, channel + + // CAPTIONS + if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['text'])) + { + foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['text'] as $caption) + { + $caption_type = null; + $caption_lang = null; + $caption_startTime = null; + $caption_endTime = null; + $caption_text = null; + if (isset($caption['attribs']['']['type'])) + { + $caption_type = $this->sanitize($caption['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($caption['attribs']['']['lang'])) + { + $caption_lang = $this->sanitize($caption['attribs']['']['lang'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($caption['attribs']['']['start'])) + { + $caption_startTime = $this->sanitize($caption['attribs']['']['start'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($caption['attribs']['']['end'])) + { + $caption_endTime = $this->sanitize($caption['attribs']['']['end'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($caption['data'])) + { + $caption_text = $this->sanitize($caption['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + $captions[] =& new $this->feed->caption_class($caption_type, $caption_lang, $caption_startTime, $caption_endTime, $caption_text); + } + if (is_array($captions)) + { + $captions = array_values(SimplePie_Misc::array_unique($captions)); + } + } + else + { + $captions = $captions_parent; + } + + // CATEGORIES + if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['category'])) + { + foreach ((array) $content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['category'] as $category) + { + $term = null; + $scheme = null; + $label = null; + if (isset($category['data'])) + { + $term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($category['attribs']['']['scheme'])) + { + $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT); + } + else + { + $scheme = 'http://search.yahoo.com/mrss/category_schema'; + } + if (isset($category['attribs']['']['label'])) + { + $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT); + } + $categories[] =& new $this->feed->category_class($term, $scheme, $label); + } + } + if (is_array($categories) && is_array($categories_parent)) + { + $categories = array_values(SimplePie_Misc::array_unique(array_merge($categories, $categories_parent))); + } + elseif (is_array($categories)) + { + $categories = array_values(SimplePie_Misc::array_unique($categories)); + } + elseif (is_array($categories_parent)) + { + $categories = array_values(SimplePie_Misc::array_unique($categories_parent)); + } + else + { + $categories = null; + } + + // COPYRIGHTS + if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'])) + { + $copyright_url = null; + $copyright_label = null; + if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['attribs']['']['url'])) + { + $copyright_url = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['data'])) + { + $copyright_label = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + $copyrights =& new $this->feed->copyright_class($copyright_url, $copyright_label); + } + else + { + $copyrights = $copyrights_parent; + } + + // CREDITS + if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['credit'])) + { + foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['credit'] as $credit) + { + $credit_role = null; + $credit_scheme = null; + $credit_name = null; + if (isset($credit['attribs']['']['role'])) + { + $credit_role = $this->sanitize($credit['attribs']['']['role'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($credit['attribs']['']['scheme'])) + { + $credit_scheme = $this->sanitize($credit['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT); + } + else + { + $credit_scheme = 'urn:ebu'; + } + if (isset($credit['data'])) + { + $credit_name = $this->sanitize($credit['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + $credits[] =& new $this->feed->credit_class($credit_role, $credit_scheme, $credit_name); + } + if (is_array($credits)) + { + $credits = array_values(SimplePie_Misc::array_unique($credits)); + } + } + else + { + $credits = $credits_parent; + } + + // DESCRIPTION + if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['description'])) + { + $description = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['description'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + else + { + $description = $description_parent; + } + + // HASHES + if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['hash'])) + { + foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['hash'] as $hash) + { + $value = null; + $algo = null; + if (isset($hash['data'])) + { + $value = $this->sanitize($hash['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($hash['attribs']['']['algo'])) + { + $algo = $this->sanitize($hash['attribs']['']['algo'], SIMPLEPIE_CONSTRUCT_TEXT); + } + else + { + $algo = 'md5'; + } + $hashes[] = $algo.':'.$value; + } + if (is_array($hashes)) + { + $hashes = array_values(SimplePie_Misc::array_unique($hashes)); + } + } + else + { + $hashes = $hashes_parent; + } + + // KEYWORDS + if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords'])) + { + if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords'][0]['data'])) + { + $temp = explode(',', $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT)); + foreach ($temp as $word) + { + $keywords[] = trim($word); + } + unset($temp); + } + if (is_array($keywords)) + { + $keywords = array_values(SimplePie_Misc::array_unique($keywords)); + } + } + else + { + $keywords = $keywords_parent; + } + + // PLAYER + if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['player'])) + { + $player = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['player'][0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI); + } + else + { + $player = $player_parent; + } + + // RATINGS + if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['rating'])) + { + foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['rating'] as $rating) + { + $rating_scheme = null; + $rating_value = null; + if (isset($rating['attribs']['']['scheme'])) + { + $rating_scheme = $this->sanitize($rating['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT); + } + else + { + $rating_scheme = 'urn:simple'; + } + if (isset($rating['data'])) + { + $rating_value = $this->sanitize($rating['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + $ratings[] =& new $this->feed->rating_class($rating_scheme, $rating_value); + } + if (is_array($ratings)) + { + $ratings = array_values(SimplePie_Misc::array_unique($ratings)); + } + } + else + { + $ratings = $ratings_parent; + } + + // RESTRICTIONS + if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['restriction'])) + { + foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['restriction'] as $restriction) + { + $restriction_relationship = null; + $restriction_type = null; + $restriction_value = null; + if (isset($restriction['attribs']['']['relationship'])) + { + $restriction_relationship = $this->sanitize($restriction['attribs']['']['relationship'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($restriction['attribs']['']['type'])) + { + $restriction_type = $this->sanitize($restriction['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($restriction['data'])) + { + $restriction_value = $this->sanitize($restriction['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + $restrictions[] =& new $this->feed->restriction_class($restriction_relationship, $restriction_type, $restriction_value); + } + if (is_array($restrictions)) + { + $restrictions = array_values(SimplePie_Misc::array_unique($restrictions)); + } + } + else + { + $restrictions = $restrictions_parent; + } + + // THUMBNAILS + if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['thumbnail'])) + { + foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['thumbnail'] as $thumbnail) + { + $thumbnails[] = $this->sanitize($thumbnail['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI); + } + if (is_array($thumbnails)) + { + $thumbnails = array_values(SimplePie_Misc::array_unique($thumbnails)); + } + } + else + { + $thumbnails = $thumbnails_parent; + } + + // TITLES + if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['title'])) + { + $title = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['title'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + else + { + $title = $title_parent; + } + + $this->data['enclosures'][] =& new $this->feed->enclosure_class($url, $type, $length, $this->feed->javascript, $bitrate, $captions, $categories, $channels, $copyrights, $credits, $description, $duration, $expression, $framerate, $hashes, $height, $keywords, $lang, $medium, $player, $ratings, $restrictions, $samplingrate, $thumbnails, $title, $width); + } + } + } + + foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'link') as $link) + { + if (isset($link['attribs']['']['href']) && !empty($link['attribs']['']['rel']) && $link['attribs']['']['rel'] == 'enclosure') + { + // Attributes + $bitrate = null; + $channels = null; + $duration = null; + $expression = null; + $framerate = null; + $height = null; + $javascript = null; + $lang = null; + $length = null; + $medium = null; + $samplingrate = null; + $type = null; + $url = null; + $width = null; + + $url = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link)); + if (isset($link['attribs']['']['type'])) + { + $type = $this->sanitize($link['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($link['attribs']['']['length'])) + { + $length = ceil($link['attribs']['']['length']); + } + + // Since we don't have group or content for these, we'll just pass the '*_parent' variables directly to the constructor + $this->data['enclosures'][] =& new $this->feed->enclosure_class($url, $type, $length, $this->feed->javascript, $bitrate, $captions_parent, $categories_parent, $channels, $copyrights_parent, $credits_parent, $description_parent, $duration_parent, $expression, $framerate, $hashes_parent, $height, $keywords_parent, $lang, $medium, $player_parent, $ratings_parent, $restrictions_parent, $samplingrate, $thumbnails_parent, $title_parent, $width); + } + } + + foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'link') as $link) + { + if (isset($link['attribs']['']['href']) && !empty($link['attribs']['']['rel']) && $link['attribs']['']['rel'] == 'enclosure') + { + // Attributes + $bitrate = null; + $channels = null; + $duration = null; + $expression = null; + $framerate = null; + $height = null; + $javascript = null; + $lang = null; + $length = null; + $medium = null; + $samplingrate = null; + $type = null; + $url = null; + $width = null; + + $url = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link)); + if (isset($link['attribs']['']['type'])) + { + $type = $this->sanitize($link['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($link['attribs']['']['length'])) + { + $length = ceil($link['attribs']['']['length']); + } + + // Since we don't have group or content for these, we'll just pass the '*_parent' variables directly to the constructor + $this->data['enclosures'][] =& new $this->feed->enclosure_class($url, $type, $length, $this->feed->javascript, $bitrate, $captions_parent, $categories_parent, $channels, $copyrights_parent, $credits_parent, $description_parent, $duration_parent, $expression, $framerate, $hashes_parent, $height, $keywords_parent, $lang, $medium, $player_parent, $ratings_parent, $restrictions_parent, $samplingrate, $thumbnails_parent, $title_parent, $width); + } + } + + if ($enclosure = $this->get_item_tags('', 'enclosure')) + { + if (isset($enclosure[0]['attribs']['']['url'])) + { + // Attributes + $bitrate = null; + $channels = null; + $duration = null; + $expression = null; + $framerate = null; + $height = null; + $javascript = null; + $lang = null; + $length = null; + $medium = null; + $samplingrate = null; + $type = null; + $url = null; + $width = null; + + $url = $this->sanitize($enclosure[0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($enclosure[0])); + if (isset($enclosure[0]['attribs']['']['type'])) + { + $type = $this->sanitize($enclosure[0]['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($enclosure[0]['attribs']['']['length'])) + { + $length = ceil($enclosure[0]['attribs']['']['length']); + } + + // Since we don't have group or content for these, we'll just pass the '*_parent' variables directly to the constructor + $this->data['enclosures'][] =& new $this->feed->enclosure_class($url, $type, $length, $this->feed->javascript, $bitrate, $captions_parent, $categories_parent, $channels, $copyrights_parent, $credits_parent, $description_parent, $duration_parent, $expression, $framerate, $hashes_parent, $height, $keywords_parent, $lang, $medium, $player_parent, $ratings_parent, $restrictions_parent, $samplingrate, $thumbnails_parent, $title_parent, $width); + } + } + + if (sizeof($this->data['enclosures']) == 0 && ($url || $type || $length || $bitrate || $captions_parent || $categories_parent || $channels || $copyrights_parent || $credits_parent || $description_parent || $duration_parent || $expression || $framerate || $hashes_parent || $height || $keywords_parent || $lang || $medium || $player_parent || $ratings_parent || $restrictions_parent || $samplingrate || $thumbnails_parent || $title_parent || $width)) + { + // Since we don't have group or content for these, we'll just pass the '*_parent' variables directly to the constructor + $this->data['enclosures'][] =& new $this->feed->enclosure_class($url, $type, $length, $this->feed->javascript, $bitrate, $captions_parent, $categories_parent, $channels, $copyrights_parent, $credits_parent, $description_parent, $duration_parent, $expression, $framerate, $hashes_parent, $height, $keywords_parent, $lang, $medium, $player_parent, $ratings_parent, $restrictions_parent, $samplingrate, $thumbnails_parent, $title_parent, $width); + } + + $this->data['enclosures'] = array_values(SimplePie_Misc::array_unique($this->data['enclosures'])); + } + if (!empty($this->data['enclosures'])) + { + return $this->data['enclosures']; + } + else + { + return null; + } + } + + function get_latitude() + { + if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'lat')) + { + return (float) $return[0]['data']; + } + elseif (($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_GEORSS, 'point')) && preg_match('/^((?:-)?[0-9]+(?:\.[0-9]+)) ((?:-)?[0-9]+(?:\.[0-9]+))$/', $return[0]['data'], $match)) + { + return (float) $match[1]; + } + else + { + return null; + } + } + + function get_longitude() + { + if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'long')) + { + return (float) $return[0]['data']; + } + elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'lon')) + { + return (float) $return[0]['data']; + } + elseif (($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_GEORSS, 'point')) && preg_match('/^((?:-)?[0-9]+(?:\.[0-9]+)) ((?:-)?[0-9]+(?:\.[0-9]+))$/', $return[0]['data'], $match)) + { + return (float) $match[2]; + } + else + { + return null; + } + } + + function get_source() + { + if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'source')) + { + return new $this->feed->source_class($this, $return[0]); + } + else + { + return null; + } + } + + /** + * Creates the add_to_* methods' return data + * + * @access private + * @param string $item_url String to prefix to the item permalink + * @param string $title_url String to prefix to the item title + * (and suffix to the item permalink) + * @return mixed URL if feed exists, false otherwise + */ + function add_to_service($item_url, $title_url = null, $summary_url = null) + { + if ($this->get_permalink() !== null) + { + $return = $this->sanitize($item_url, SIMPLEPIE_CONSTRUCT_IRI) . rawurlencode($this->get_permalink()); + if ($title_url !== null && $this->get_title() !== null) + { + $return .= $this->sanitize($title_url, SIMPLEPIE_CONSTRUCT_IRI) . rawurlencode($this->get_title()); + } + if ($summary_url !== null && $this->get_description() !== null) + { + $return .= $this->sanitize($summary_url, SIMPLEPIE_CONSTRUCT_IRI) . rawurlencode($this->get_description()); + } + return $return; + } + else + { + return null; + } + } + + function add_to_blinklist() + { + return $this->add_to_service('http://www.blinklist.com/index.php?Action=Blink/addblink.php&Description=&Url=', '&Title='); + } + + function add_to_blogmarks() + { + return $this->add_to_service('http://blogmarks.net/my/new.php?mini=1&simple=1&url=', '&title='); + } + + function add_to_delicious() + { + return $this->add_to_service('http://del.icio.us/post/?v=4&url=', '&title='); + } + + function add_to_digg() + { + return $this->add_to_service('http://digg.com/submit?url=', '&title=', '&bodytext='); + } + + function add_to_furl() + { + return $this->add_to_service('http://www.furl.net/storeIt.jsp?u=', '&t='); + } + + function add_to_magnolia() + { + return $this->add_to_service('http://ma.gnolia.com/bookmarklet/add?url=', '&title='); + } + + function add_to_myweb20() + { + return $this->add_to_service('http://myweb2.search.yahoo.com/myresults/bookmarklet?u=', '&t='); + } + + function add_to_newsvine() + { + return $this->add_to_service('http://www.newsvine.com/_wine/save?u=', '&h='); + } + + function add_to_reddit() + { + return $this->add_to_service('http://reddit.com/submit?url=', '&title='); + } + + function add_to_segnalo() + { + return $this->add_to_service('http://segnalo.com/post.html.php?url=', '&title='); + } + + function add_to_simpy() + { + return $this->add_to_service('http://www.simpy.com/simpy/LinkAdd.do?href=', '&title='); + } + + function add_to_spurl() + { + return $this->add_to_service('http://www.spurl.net/spurl.php?v=3&url=', '&title='); + } + + function add_to_wists() + { + return $this->add_to_service('http://wists.com/r.php?c=&r=', '&title='); + } + + function search_technorati() + { + return $this->add_to_service('http://www.technorati.com/search/'); + } +} + +class SimplePie_Source +{ + var $item; + var $data = array(); + + function SimplePie_Source($item, $data) + { + $this->item = $item; + $this->data = $data; + } + + function __toString() + { + return md5(serialize($this->data)); + } + + /** + * Remove items that link back to this before destroying this object + */ + function __destruct() + { + unset($this->item); + } + + function get_source_tags($namespace, $tag) + { + if (isset($this->data['child'][$namespace][$tag])) + { + return $this->data['child'][$namespace][$tag]; + } + else + { + return null; + } + } + + function get_base($element = array()) + { + return $this->item->get_base($element); + } + + function sanitize($data, $type, $base = '') + { + return $this->item->sanitize($data, $type, $base); + } + + function get_item() + { + return $this->item; + } + + function get_title() + { + if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'title')) + { + return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_10_construct_type($return[0]['attribs']), $this->get_base($return[0])); + } + elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'title')) + { + return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_03_construct_type($return[0]['attribs']), $this->get_base($return[0])); + } + elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'title')) + { + return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0])); + } + elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'title')) + { + return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0])); + } + elseif ($return = $this->get_source_tags('', 'title')) + { + return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0])); + } + elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_11, 'title')) + { + return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_10, 'title')) + { + return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + else + { + return null; + } + } + + function get_category($key = 0) + { + $categories = $this->get_categories(); + if (isset($categories[$key])) + { + return $categories[$key]; + } + else + { + return null; + } + } + + function get_categories() + { + $categories = array(); + + foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'category') as $category) + { + $term = null; + $scheme = null; + $label = null; + if (isset($category['attribs']['']['term'])) + { + $term = $this->sanitize($category['attribs']['']['term'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($category['attribs']['']['scheme'])) + { + $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($category['attribs']['']['label'])) + { + $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT); + } + $categories[] =& new $this->item->feed->category_class($term, $scheme, $label); + } + foreach ((array) $this->get_source_tags('', 'category') as $category) + { + $categories[] =& new $this->item->feed->category_class($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null); + } + foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_11, 'subject') as $category) + { + $categories[] =& new $this->item->feed->category_class($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null); + } + foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_10, 'subject') as $category) + { + $categories[] =& new $this->item->feed->category_class($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null); + } + + if (!empty($categories)) + { + return SimplePie_Misc::array_unique($categories); + } + else + { + return null; + } + } + + function get_author($key = 0) + { + $authors = $this->get_authors(); + if (isset($authors[$key])) + { + return $authors[$key]; + } + else + { + return null; + } + } + + function get_authors() + { + $authors = array(); + foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'author') as $author) + { + $name = null; + $uri = null; + $email = null; + if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'])) + { + $name = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data'])) + { + $uri = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0])); + } + if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'])) + { + $email = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if ($name !== null || $email !== null || $uri !== null) + { + $authors[] =& new $this->item->feed->author_class($name, $uri, $email); + } + } + if ($author = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'author')) + { + $name = null; + $url = null; + $email = null; + if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'])) + { + $name = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data'])) + { + $url = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0])); + } + if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'])) + { + $email = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if ($name !== null || $email !== null || $url !== null) + { + $authors[] =& new $this->item->feed->author_class($name, $url, $email); + } + } + foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_11, 'creator') as $author) + { + $authors[] =& new $this->item->feed->author_class($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null); + } + foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_10, 'creator') as $author) + { + $authors[] =& new $this->item->feed->author_class($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null); + } + foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'author') as $author) + { + $authors[] =& new $this->item->feed->author_class($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null); + } + + if (!empty($authors)) + { + return SimplePie_Misc::array_unique($authors); + } + else + { + return null; + } + } + + function get_contributor($key = 0) + { + $contributors = $this->get_contributors(); + if (isset($contributors[$key])) + { + return $contributors[$key]; + } + else + { + return null; + } + } + + function get_contributors() + { + $contributors = array(); + foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'contributor') as $contributor) + { + $name = null; + $uri = null; + $email = null; + if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'])) + { + $name = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data'])) + { + $uri = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0])); + } + if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'])) + { + $email = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if ($name !== null || $email !== null || $uri !== null) + { + $contributors[] =& new $this->item->feed->author_class($name, $uri, $email); + } + } + foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'contributor') as $contributor) + { + $name = null; + $url = null; + $email = null; + if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'])) + { + $name = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data'])) + { + $url = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0])); + } + if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'])) + { + $email = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if ($name !== null || $email !== null || $url !== null) + { + $contributors[] =& new $this->item->feed->author_class($name, $url, $email); + } + } + + if (!empty($contributors)) + { + return SimplePie_Misc::array_unique($contributors); + } + else + { + return null; + } + } + + function get_link($key = 0, $rel = 'alternate') + { + $links = $this->get_links($rel); + if (isset($links[$key])) + { + return $links[$key]; + } + else + { + return null; + } + } + + /** + * Added for parity between the parent-level and the item/entry-level. + */ + function get_permalink() + { + return $this->get_link(0); + } + + function get_links($rel = 'alternate') + { + if (!isset($this->data['links'])) + { + $this->data['links'] = array(); + if ($links = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'link')) + { + foreach ($links as $link) + { + if (isset($link['attribs']['']['href'])) + { + $link_rel = (isset($link['attribs']['']['rel'])) ? $link['attribs']['']['rel'] : 'alternate'; + $this->data['links'][$link_rel][] = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link)); + } + } + } + if ($links = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'link')) + { + foreach ($links as $link) + { + if (isset($link['attribs']['']['href'])) + { + $link_rel = (isset($link['attribs']['']['rel'])) ? $link['attribs']['']['rel'] : 'alternate'; + $this->data['links'][$link_rel][] = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link)); + + } + } + } + if ($links = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'link')) + { + $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0])); + } + if ($links = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'link')) + { + $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0])); + } + if ($links = $this->get_source_tags('', 'link')) + { + $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0])); + } + + $keys = array_keys($this->data['links']); + foreach ($keys as $key) + { + if (SimplePie_Misc::is_isegment_nz_nc($key)) + { + if (isset($this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key])) + { + $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key] = array_merge($this->data['links'][$key], $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key]); + $this->data['links'][$key] =& $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key]; + } + else + { + $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key] =& $this->data['links'][$key]; + } + } + elseif (substr($key, 0, 41) == SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY) + { + $this->data['links'][substr($key, 41)] =& $this->data['links'][$key]; + } + $this->data['links'][$key] = array_unique($this->data['links'][$key]); + } + } + + if (isset($this->data['links'][$rel])) + { + return $this->data['links'][$rel]; + } + else + { + return null; + } + } + + function get_description() + { + if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'subtitle')) + { + return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_10_construct_type($return[0]['attribs']), $this->get_base($return[0])); + } + elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'tagline')) + { + return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_03_construct_type($return[0]['attribs']), $this->get_base($return[0])); + } + elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'description')) + { + return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0])); + } + elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'description')) + { + return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0])); + } + elseif ($return = $this->get_source_tags('', 'description')) + { + return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0])); + } + elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_11, 'description')) + { + return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_10, 'description')) + { + return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'summary')) + { + return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0])); + } + elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'subtitle')) + { + return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0])); + } + else + { + return null; + } + } + + function get_copyright() + { + if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'rights')) + { + return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_10_construct_type($return[0]['attribs']), $this->get_base($return[0])); + } + elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'copyright')) + { + return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_03_construct_type($return[0]['attribs']), $this->get_base($return[0])); + } + elseif ($return = $this->get_source_tags('', 'copyright')) + { + return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_11, 'rights')) + { + return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_10, 'rights')) + { + return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + else + { + return null; + } + } + + function get_language() + { + if ($return = $this->get_source_tags('', 'language')) + { + return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_11, 'language')) + { + return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_10, 'language')) + { + return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + elseif (isset($this->data['xml_lang'])) + { + return $this->sanitize($this->data['xml_lang'], SIMPLEPIE_CONSTRUCT_TEXT); + } + else + { + return null; + } + } + + function get_latitude() + { + if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'lat')) + { + return (float) $return[0]['data']; + } + elseif (($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_GEORSS, 'point')) && preg_match('/^((?:-)?[0-9]+(?:\.[0-9]+)) ((?:-)?[0-9]+(?:\.[0-9]+))$/', $return[0]['data'], $match)) + { + return (float) $match[1]; + } + else + { + return null; + } + } + + function get_longitude() + { + if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'long')) + { + return (float) $return[0]['data']; + } + elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'lon')) + { + return (float) $return[0]['data']; + } + elseif (($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_GEORSS, 'point')) && preg_match('/^((?:-)?[0-9]+(?:\.[0-9]+)) ((?:-)?[0-9]+(?:\.[0-9]+))$/', $return[0]['data'], $match)) + { + return (float) $match[2]; + } + else + { + return null; + } + } + + function get_image_url() + { + if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'image')) + { + return $this->sanitize($return[0]['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI); + } + elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'logo')) + { + return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0])); + } + elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'icon')) + { + return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0])); + } + else + { + return null; + } + } +} + +class SimplePie_Author +{ + var $name; + var $link; + var $email; + + // Constructor, used to input the data + function SimplePie_Author($name = null, $link = null, $email = null) + { + $this->name = $name; + $this->link = $link; + $this->email = $email; + } + + function __toString() + { + // There is no $this->data here + return md5(serialize($this)); + } + + function get_name() + { + if ($this->name !== null) + { + return $this->name; + } + else + { + return null; + } + } + + function get_link() + { + if ($this->link !== null) + { + return $this->link; + } + else + { + return null; + } + } + + function get_email() + { + if ($this->email !== null) + { + return $this->email; + } + else + { + return null; + } + } +} + +class SimplePie_Category +{ + var $term; + var $scheme; + var $label; + + // Constructor, used to input the data + function SimplePie_Category($term = null, $scheme = null, $label = null) + { + $this->term = $term; + $this->scheme = $scheme; + $this->label = $label; + } + + function __toString() + { + // There is no $this->data here + return md5(serialize($this)); + } + + function get_term() + { + if ($this->term !== null) + { + return $this->term; + } + else + { + return null; + } + } + + function get_scheme() + { + if ($this->scheme !== null) + { + return $this->scheme; + } + else + { + return null; + } + } + + function get_label() + { + if ($this->label !== null) + { + return $this->label; + } + else + { + return $this->get_term(); + } + } +} + +class SimplePie_Enclosure +{ + var $bitrate; + var $captions; + var $categories; + var $channels; + var $copyright; + var $credits; + var $description; + var $duration; + var $expression; + var $framerate; + var $handler; + var $hashes; + var $height; + var $javascript; + var $keywords; + var $lang; + var $length; + var $link; + var $medium; + var $player; + var $ratings; + var $restrictions; + var $samplingrate; + var $thumbnails; + var $title; + var $type; + var $width; + + // Constructor, used to input the data + function SimplePie_Enclosure($link = null, $type = null, $length = null, $javascript = null, $bitrate = null, $captions = null, $categories = null, $channels = null, $copyright = null, $credits = null, $description = null, $duration = null, $expression = null, $framerate = null, $hashes = null, $height = null, $keywords = null, $lang = null, $medium = null, $player = null, $ratings = null, $restrictions = null, $samplingrate = null, $thumbnails = null, $title = null, $width = null) + { + $this->bitrate = $bitrate; + $this->captions = $captions; + $this->categories = $categories; + $this->channels = $channels; + $this->copyright = $copyright; + $this->credits = $credits; + $this->description = $description; + $this->duration = $duration; + $this->expression = $expression; + $this->framerate = $framerate; + $this->hashes = $hashes; + $this->height = $height; + $this->javascript = $javascript; + $this->keywords = $keywords; + $this->lang = $lang; + $this->length = $length; + $this->link = $link; + $this->medium = $medium; + $this->player = $player; + $this->ratings = $ratings; + $this->restrictions = $restrictions; + $this->samplingrate = $samplingrate; + $this->thumbnails = $thumbnails; + $this->title = $title; + $this->type = $type; + $this->width = $width; + if (class_exists('idna_convert')) + { + $idn =& new idna_convert; + $parsed = SimplePie_Misc::parse_url($link); + $this->link = SimplePie_Misc::compress_parse_url($parsed['scheme'], $idn->encode($parsed['authority']), $parsed['path'], $parsed['query'], $parsed['fragment']); + } + $this->handler = $this->get_handler(); // Needs to load last + } + + function __toString() + { + // There is no $this->data here + return md5(serialize($this)); + } + + function get_bitrate() + { + if ($this->bitrate !== null) + { + return $this->bitrate; + } + else + { + return null; + } + } + + function get_caption($key = 0) + { + $captions = $this->get_captions(); + if (isset($captions[$key])) + { + return $captions[$key]; + } + else + { + return null; + } + } + + function get_captions() + { + if ($this->captions !== null) + { + return $this->captions; + } + else + { + return null; + } + } + + function get_category($key = 0) + { + $categories = $this->get_categories(); + if (isset($categories[$key])) + { + return $categories[$key]; + } + else + { + return null; + } + } + + function get_categories() + { + if ($this->categories !== null) + { + return $this->categories; + } + else + { + return null; + } + } + + function get_channels() + { + if ($this->channels !== null) + { + return $this->channels; + } + else + { + return null; + } + } + + function get_copyright() + { + if ($this->copyright !== null) + { + return $this->copyright; + } + else + { + return null; + } + } + + function get_credit($key = 0) + { + $credits = $this->get_credits(); + if (isset($credits[$key])) + { + return $credits[$key]; + } + else + { + return null; + } + } + + function get_credits() + { + if ($this->credits !== null) + { + return $this->credits; + } + else + { + return null; + } + } + + function get_description() + { + if ($this->description !== null) + { + return $this->description; + } + else + { + return null; + } + } + + function get_duration($convert = false) + { + if ($this->duration !== null) + { + if ($convert) + { + $time = SimplePie_Misc::time_hms($this->duration); + return $time; + } + else + { + return $this->duration; + } + } + else + { + return null; + } + } + + function get_expression() + { + if ($this->expression !== null) + { + return $this->expression; + } + else + { + return 'full'; + } + } + + function get_extension() + { + if ($this->link !== null) + { + $url = SimplePie_Misc::parse_url($this->link); + if ($url['path'] !== '') + { + return pathinfo($url['path'], PATHINFO_EXTENSION); + } + } + return null; + } + + function get_framerate() + { + if ($this->framerate !== null) + { + return $this->framerate; + } + else + { + return null; + } + } + + function get_handler() + { + return $this->get_real_type(true); + } + + function get_hash($key = 0) + { + $hashes = $this->get_hashes(); + if (isset($hashes[$key])) + { + return $hashes[$key]; + } + else + { + return null; + } + } + + function get_hashes() + { + if ($this->hashes !== null) + { + return $this->hashes; + } + else + { + return null; + } + } + + function get_height() + { + if ($this->height !== null) + { + return $this->height; + } + else + { + return null; + } + } + + function get_language() + { + if ($this->lang !== null) + { + return $this->lang; + } + else + { + return null; + } + } + + function get_keyword($key = 0) + { + $keywords = $this->get_keywords(); + if (isset($keywords[$key])) + { + return $keywords[$key]; + } + else + { + return null; + } + } + + function get_keywords() + { + if ($this->keywords !== null) + { + return $this->keywords; + } + else + { + return null; + } + } + + function get_length() + { + if ($this->length !== null) + { + return $this->length; + } + else + { + return null; + } + } + + function get_link() + { + if ($this->link !== null) + { + return urldecode($this->link); + } + else + { + return null; + } + } + + function get_medium() + { + if ($this->medium !== null) + { + return $this->medium; + } + else + { + return null; + } + } + + function get_player() + { + if ($this->player !== null) + { + return $this->player; + } + else + { + return null; + } + } + + function get_rating($key = 0) + { + $ratings = $this->get_ratings(); + if (isset($ratings[$key])) + { + return $ratings[$key]; + } + else + { + return null; + } + } + + function get_ratings() + { + if ($this->ratings !== null) + { + return $this->ratings; + } + else + { + return null; + } + } + + function get_restriction($key = 0) + { + $restrictions = $this->get_restrictions(); + if (isset($restrictions[$key])) + { + return $restrictions[$key]; + } + else + { + return null; + } + } + + function get_restrictions() + { + if ($this->restrictions !== null) + { + return $this->restrictions; + } + else + { + return null; + } + } + + function get_sampling_rate() + { + if ($this->samplingrate !== null) + { + return $this->samplingrate; + } + else + { + return null; + } + } + + function get_size() + { + $length = $this->get_length(); + if ($length !== null) + { + return round($length/1048576, 2); + } + else + { + return null; + } + } + + function get_thumbnail($key = 0) + { + $thumbnails = $this->get_thumbnails(); + if (isset($thumbnails[$key])) + { + return $thumbnails[$key]; + } + else + { + return null; + } + } + + function get_thumbnails() + { + if ($this->thumbnails !== null) + { + return $this->thumbnails; + } + else + { + return null; + } + } + + function get_title() + { + if ($this->title !== null) + { + return $this->title; + } + else + { + return null; + } + } + + function get_type() + { + if ($this->type !== null) + { + return $this->type; + } + else + { + return null; + } + } + + function get_width() + { + if ($this->width !== null) + { + return $this->width; + } + else + { + return null; + } + } + + function native_embed($options='') + { + return $this->embed($options, true); + } + + /** + * @todo If the dimensions for media:content are defined, use them when width/height are set to 'auto'. + */ + function embed($options = '', $native = false) + { + // Set up defaults + $audio = ''; + $video = ''; + $alt = ''; + $altclass = ''; + $loop = 'false'; + $width = 'auto'; + $height = 'auto'; + $bgcolor = '#ffffff'; + $mediaplayer = ''; + $widescreen = false; + $handler = $this->get_handler(); + $type = $this->get_real_type(); + + // Process options and reassign values as necessary + if (is_array($options)) + { + extract($options); + } + else + { + $options = explode(',', $options); + foreach($options as $option) + { + $opt = explode(':', $option, 2); + if (isset($opt[0], $opt[1])) + { + $opt[0] = trim($opt[0]); + $opt[1] = trim($opt[1]); + switch ($opt[0]) + { + case 'audio': + $audio = $opt[1]; + break; + + case 'video': + $video = $opt[1]; + break; + + case 'alt': + $alt = $opt[1]; + break; + + case 'altclass': + $altclass = $opt[1]; + break; + + case 'loop': + $loop = $opt[1]; + break; + + case 'width': + $width = $opt[1]; + break; + + case 'height': + $height = $opt[1]; + break; + + case 'bgcolor': + $bgcolor = $opt[1]; + break; + + case 'mediaplayer': + $mediaplayer = $opt[1]; + break; + + case 'widescreen': + $widescreen = $opt[1]; + break; + } + } + } + } + + $mime = explode('/', $type, 2); + $mime = $mime[0]; + + // Process values for 'auto' + if ($width == 'auto') + { + if ($mime == 'video') + { + if ($height == 'auto') + { + $width = 480; + } + elseif ($widescreen) + { + $width = round((intval($height)/9)*16); + } + else + { + $width = round((intval($height)/3)*4); + } + } + else + { + $width = '100%'; + } + } + + if ($height == 'auto') + { + if ($mime == 'audio') + { + $height = 0; + } + elseif ($mime == 'video') + { + if ($width == 'auto') + { + if ($widescreen) + { + $height = 270; + } + else + { + $height = 360; + } + } + elseif ($widescreen) + { + $height = round((intval($width)/16)*9); + } + else + { + $height = round((intval($width)/4)*3); + } + } + else + { + $height = 376; + } + } + elseif ($mime == 'audio') + { + $height = 0; + } + + // Set proper placeholder value + if ($mime == 'audio') + { + $placeholder = $audio; + } + elseif ($mime == 'video') + { + $placeholder = $video; + } + + $embed = ''; + + // Make sure the JS library is included + if (!$native) + { + static $javascript_outputted = null; + if (!$javascript_outputted && $this->javascript) + { + $embed .= ''; + $javascript_outputted = true; + } + } + + // Odeo Feed MP3's + if ($handler == 'odeo') + { + if ($native) + { + $embed .= ''; + } + else + { + $embed .= ''; + } + } + + // Flash + elseif ($handler == 'flash') + { + if ($native) + { + $embed .= "get_link() . "\" pluginspage=\"http://adobe.com/go/getflashplayer\" type=\"$type\" quality=\"high\" width=\"$width\" height=\"$height\" bgcolor=\"$bgcolor\" loop=\"$loop\">"; + } + else + { + $embed .= ""; + } + } + + // Flash Media Player file types. + // Preferred handler for MP3 file types. + elseif ($handler == 'fmedia' || ($handler == 'mp3' && $mediaplayer != '')) + { + $height += 20; + if ($native) + { + $embed .= "get_link().'?file_extension=.'.$this->get_extension()) . "&autostart=false&repeat=$loop&showdigits=true&showfsbutton=false\">"; + } + else + { + $embed .= ""; + } + } + + // QuickTime 7 file types. Need to test with QuickTime 6. + // Only handle MP3's if the Flash Media Player is not present. + elseif ($handler == 'quicktime' || ($handler == 'mp3' && $mediaplayer == '')) + { + $height += 16; + if ($native) + { + if ($placeholder != ""){ + $embed .= "get_link() . "\" src=\"$placeholder\" width=\"$width\" height=\"$height\" autoplay=\"false\" target=\"myself\" controller=\"false\" loop=\"$loop\" scale=\"aspect\" bgcolor=\"$bgcolor\" pluginspage=\"http://apple.com/quicktime/download/\">"; + } + else { + $embed .= "get_link() . "\" width=\"$width\" height=\"$height\" autoplay=\"false\" target=\"myself\" controller=\"true\" loop=\"$loop\" scale=\"aspect\" bgcolor=\"$bgcolor\" pluginspage=\"http://apple.com/quicktime/download/\">"; + } + } + else + { + $embed .= ""; + } + } + + // Windows Media + elseif ($handler == 'wmedia') + { + $height += 45; + if ($native) + { + $embed .= "get_link() . "\" autosize=\"1\" width=\"$width\" height=\"$height\" showcontrols=\"1\" showstatusbar=\"0\" showdisplay=\"0\" autostart=\"0\">"; + } + else + { + $embed .= ""; + } + } + + // Everything else + else $embed .= '' . $alt . ''; + + return $embed; + } + + function get_real_type($find_handler = false) + { + // If it's Odeo, let's get it out of the way. + if (substr(strtolower($this->get_link()), 0, 15) == 'http://odeo.com') + { + return 'odeo'; + } + + // Mime-types by handler. + $types_flash = array('application/x-shockwave-flash', 'application/futuresplash'); // Flash + $types_fmedia = array('video/flv', 'video/x-flv','flv-application/octet-stream'); // Flash Media Player + $types_quicktime = array('audio/3gpp', 'audio/3gpp2', 'audio/aac', 'audio/x-aac', 'audio/aiff', 'audio/x-aiff', 'audio/mid', 'audio/midi', 'audio/x-midi', 'audio/mp4', 'audio/m4a', 'audio/x-m4a', 'audio/wav', 'audio/x-wav', 'video/3gpp', 'video/3gpp2', 'video/m4v', 'video/x-m4v', 'video/mp4', 'video/mpeg', 'video/x-mpeg', 'video/quicktime', 'video/sd-video'); // QuickTime + $types_wmedia = array('application/asx', 'application/x-mplayer2', 'audio/x-ms-wma', 'audio/x-ms-wax', 'video/x-ms-asf-plugin', 'video/x-ms-asf', 'video/x-ms-wm', 'video/x-ms-wmv', 'video/x-ms-wvx'); // Windows Media + $types_mp3 = array('audio/mp3', 'audio/x-mp3', 'audio/mpeg', 'audio/x-mpeg'); // MP3 + + if ($this->get_type() !== null) + { + $type = strtolower($this->type); + } + else + { + $type = null; + } + + // If we encounter an unsupported mime-type, check the file extension and guess intelligently. + if (!in_array($type, array_merge($types_flash, $types_fmedia, $types_quicktime, $types_wmedia, $types_mp3))) + { + switch (strtolower($this->get_extension())) + { + // Audio mime-types + case 'aac': + case 'adts': + $type = 'audio/acc'; + break; + + case 'aif': + case 'aifc': + case 'aiff': + case 'cdda': + $type = 'audio/aiff'; + break; + + case 'bwf': + $type = 'audio/wav'; + break; + + case 'kar': + case 'mid': + case 'midi': + case 'smf': + $type = 'audio/midi'; + break; + + case 'm4a': + $type = 'audio/x-m4a'; + break; + + case 'mp3': + case 'swa': + $type = 'audio/mp3'; + break; + + case 'wav': + $type = 'audio/wav'; + break; + + case 'wax': + $type = 'audio/x-ms-wax'; + break; + + case 'wma': + $type = 'audio/x-ms-wma'; + break; + + // Video mime-types + case '3gp': + case '3gpp': + $type = 'video/3gpp'; + break; + + case '3g2': + case '3gp2': + $type = 'video/3gpp2'; + break; + + case 'asf': + $type = 'video/x-ms-asf'; + break; + + case 'flv': + $type = 'video/x-flv'; + break; + + case 'm1a': + case 'm1s': + case 'm1v': + case 'm15': + case 'm75': + case 'mp2': + case 'mpa': + case 'mpeg': + case 'mpg': + case 'mpm': + case 'mpv': + $type = 'video/mpeg'; + break; + + case 'm4v': + $type = 'video/x-m4v'; + break; + + case 'mov': + case 'qt': + $type = 'video/quicktime'; + break; + + case 'mp4': + case 'mpg4': + $type = 'video/mp4'; + break; + + case 'sdv': + $type = 'video/sd-video'; + break; + + case 'wm': + $type = 'video/x-ms-wm'; + break; + + case 'wmv': + $type = 'video/x-ms-wmv'; + break; + + case 'wvx': + $type = 'video/x-ms-wvx'; + break; + + // Flash mime-types + case 'spl': + $type = 'application/futuresplash'; + break; + + case 'swf': + $type = 'application/x-shockwave-flash'; + break; + } + } + + if ($find_handler) + { + if (in_array($type, $types_flash)) + { + return 'flash'; + } + elseif (in_array($type, $types_fmedia)) + { + return 'fmedia'; + } + elseif (in_array($type, $types_quicktime)) + { + return 'quicktime'; + } + elseif (in_array($type, $types_wmedia)) + { + return 'wmedia'; + } + elseif (in_array($type, $types_mp3)) + { + return 'mp3'; + } + else + { + return null; + } + } + else + { + return $type; + } + } +} + +class SimplePie_Caption +{ + var $type; + var $lang; + var $startTime; + var $endTime; + var $text; + + // Constructor, used to input the data + function SimplePie_Caption($type = null, $lang = null, $startTime = null, $endTime = null, $text = null) + { + $this->type = $type; + $this->lang = $lang; + $this->startTime = $startTime; + $this->endTime = $endTime; + $this->text = $text; + } + + function __toString() + { + // There is no $this->data here + return md5(serialize($this)); + } + + function get_endtime() + { + if ($this->endTime !== null) + { + return $this->endTime; + } + else + { + return null; + } + } + + function get_language() + { + if ($this->lang !== null) + { + return $this->lang; + } + else + { + return null; + } + } + + function get_starttime() + { + if ($this->startTime !== null) + { + return $this->startTime; + } + else + { + return null; + } + } + + function get_text() + { + if ($this->text !== null) + { + return $this->text; + } + else + { + return null; + } + } + + function get_type() + { + if ($this->type !== null) + { + return $this->type; + } + else + { + return null; + } + } +} + +class SimplePie_Credit +{ + var $role; + var $scheme; + var $name; + + // Constructor, used to input the data + function SimplePie_Credit($role = null, $scheme = null, $name = null) + { + $this->role = $role; + $this->scheme = $scheme; + $this->name = $name; + } + + function __toString() + { + // There is no $this->data here + return md5(serialize($this)); + } + + function get_role() + { + if ($this->role !== null) + { + return $this->role; + } + else + { + return null; + } + } + + function get_scheme() + { + if ($this->scheme !== null) + { + return $this->scheme; + } + else + { + return null; + } + } + + function get_name() + { + if ($this->name !== null) + { + return $this->name; + } + else + { + return null; + } + } +} + +class SimplePie_Copyright +{ + var $url; + var $label; + + // Constructor, used to input the data + function SimplePie_Copyright($url = null, $label = null) + { + $this->url = $url; + $this->label = $label; + } + + function __toString() + { + // There is no $this->data here + return md5(serialize($this)); + } + + function get_url() + { + if ($this->url !== null) + { + return $this->url; + } + else + { + return null; + } + } + + function get_attribution() + { + if ($this->label !== null) + { + return $this->label; + } + else + { + return null; + } + } +} + +class SimplePie_Rating +{ + var $scheme; + var $value; + + // Constructor, used to input the data + function SimplePie_Rating($scheme = null, $value = null) + { + $this->scheme = $scheme; + $this->value = $value; + } + + function __toString() + { + // There is no $this->data here + return md5(serialize($this)); + } + + function get_scheme() + { + if ($this->scheme !== null) + { + return $this->scheme; + } + else + { + return null; + } + } + + function get_value() + { + if ($this->value !== null) + { + return $this->value; + } + else + { + return null; + } + } +} + +class SimplePie_Restriction +{ + var $relationship; + var $type; + var $value; + + // Constructor, used to input the data + function SimplePie_Restriction($relationship = null, $type = null, $value = null) + { + $this->relationship = $relationship; + $this->type = $type; + $this->value = $value; + } + + function __toString() + { + // There is no $this->data here + return md5(serialize($this)); + } + + function get_relationship() + { + if ($this->relationship !== null) + { + return $this->relationship; + } + else + { + return null; + } + } + + function get_type() + { + if ($this->type !== null) + { + return $this->type; + } + else + { + return null; + } + } + + function get_value() + { + if ($this->value !== null) + { + return $this->value; + } + else + { + return null; + } + } +} + +/** + * @todo Move to properly supporting RFC2616 (HTTP/1.1) + */ +class SimplePie_File +{ + var $url; + var $useragent; + var $success = true; + var $headers = array(); + var $body; + var $status_code; + var $redirects = 0; + var $error; + var $method = SIMPLEPIE_FILE_SOURCE_NONE; + + function SimplePie_File($url, $timeout = 10, $redirects = 5, $headers = null, $useragent = null, $force_fsockopen = false) + { + if (class_exists('idna_convert')) + { + $idn =& new idna_convert; + $parsed = SimplePie_Misc::parse_url($url); + $url = SimplePie_Misc::compress_parse_url($parsed['scheme'], $idn->encode($parsed['authority']), $parsed['path'], $parsed['query'], $parsed['fragment']); + } + $this->url = $url; + $this->useragent = $useragent; + if (preg_match('/^http(s)?:\/\//i', $url)) + { + if ($useragent === null) + { + $useragent = ini_get('user_agent'); + $this->useragent = $useragent; + } + if (!is_array($headers)) + { + $headers = array(); + } + if (!$force_fsockopen && function_exists('curl_exec')) + { + $this->method = SIMPLEPIE_FILE_SOURCE_REMOTE | SIMPLEPIE_FILE_SOURCE_CURL; + $fp = curl_init(); + $headers2 = array(); + foreach ($headers as $key => $value) + { + $headers2[] = "$key: $value"; + } + if (version_compare(SimplePie_Misc::get_curl_version(), '7.10.5', '>=')) + { + curl_setopt($fp, CURLOPT_ENCODING, ''); + } + curl_setopt($fp, CURLOPT_URL, $url); + curl_setopt($fp, CURLOPT_HEADER, 1); + curl_setopt($fp, CURLOPT_RETURNTRANSFER, 1); + curl_setopt($fp, CURLOPT_TIMEOUT, $timeout); + curl_setopt($fp, CURLOPT_CONNECTTIMEOUT, $timeout); + curl_setopt($fp, CURLOPT_REFERER, $url); + curl_setopt($fp, CURLOPT_USERAGENT, $useragent); + curl_setopt($fp, CURLOPT_HTTPHEADER, $headers2); + if (!ini_get('open_basedir') && !ini_get('safe_mode') && version_compare(SimplePie_Misc::get_curl_version(), '7.15.2', '>=')) + { + curl_setopt($fp, CURLOPT_FOLLOWLOCATION, 1); + curl_setopt($fp, CURLOPT_MAXREDIRS, $redirects); + } + + $this->headers = curl_exec($fp); + if (curl_errno($fp) == 23 || curl_errno($fp) == 61) + { + curl_setopt($fp, CURLOPT_ENCODING, 'none'); + $this->headers = curl_exec($fp); + } + if (curl_errno($fp)) + { + $this->error = 'cURL error ' . curl_errno($fp) . ': ' . curl_error($fp); + $this->success = false; + } + else + { + $info = curl_getinfo($fp); + curl_close($fp); + $this->headers = explode("\r\n\r\n", $this->headers, $info['redirect_count'] + 1); + $this->headers = array_pop($this->headers); + $parser =& new SimplePie_HTTP_Parser($this->headers); + if ($parser->parse()) + { + $this->headers = $parser->headers; + $this->body = $parser->body; + $this->status_code = $parser->status_code; + if (($this->status_code == 300 || $this->status_code == 301 || $this->status_code == 302 || $this->status_code == 303 || $this->status_code == 307 || $this->status_code > 307 && $this->status_code < 400) && isset($this->headers['location']) && $this->redirects < $redirects) + { + $this->redirects++; + $location = SimplePie_Misc::absolutize_url($this->headers['location'], $url); + return $this->SimplePie_File($location, $timeout, $redirects, $headers, $useragent, $force_fsockopen); + } + } + } + } + else + { + $this->method = SIMPLEPIE_FILE_SOURCE_REMOTE | SIMPLEPIE_FILE_SOURCE_FSOCKOPEN; + $url_parts = parse_url($url); + if (isset($url_parts['scheme']) && strtolower($url_parts['scheme']) == 'https') + { + $url_parts['host'] = "ssl://$url_parts[host]"; + $url_parts['port'] = 443; + } + if (!isset($url_parts['port'])) + { + $url_parts['port'] = 80; + } + $fp = @fsockopen($url_parts['host'], $url_parts['port'], $errno, $errstr, $timeout); + if (!$fp) + { + $this->error = 'fsockopen error: ' . $errstr; + $this->success = false; + } + else + { + stream_set_timeout($fp, $timeout); + if (isset($url_parts['path'])) + { + if (isset($url_parts['query'])) + { + $get = "$url_parts[path]?$url_parts[query]"; + } + else + { + $get = $url_parts['path']; + } + } + else + { + $get = '/'; + } + $out = "GET $get HTTP/1.0\r\n"; + $out .= "Host: $url_parts[host]\r\n"; + $out .= "User-Agent: $useragent\r\n"; + if (extension_loaded('zlib')) + { + $out .= "Accept-Encoding: x-gzip,gzip,deflate\r\n"; + } + + if (isset($url_parts['user']) && isset($url_parts['pass'])) + { + $out .= "Authorization: Basic " . base64_encode("$url_parts[user]:$url_parts[pass]") . "\r\n"; + } + foreach ($headers as $key => $value) + { + $out .= "$key: $value\r\n"; + } + $out .= "Connection: Close\r\n\r\n"; + fwrite($fp, $out); + + $info = stream_get_meta_data($fp); + + $this->headers = ''; + while (!$info['eof'] && !$info['timed_out']) + { + $this->headers .= fread($fp, 1160); + $info = stream_get_meta_data($fp); + } + if (!$info['timed_out']) + { + $parser =& new SimplePie_HTTP_Parser($this->headers); + if ($parser->parse()) + { + $this->headers = $parser->headers; + $this->body = $parser->body; + $this->status_code = $parser->status_code; + if (($this->status_code == 300 || $this->status_code == 301 || $this->status_code == 302 || $this->status_code == 303 || $this->status_code == 307 || $this->status_code > 307 && $this->status_code < 400) && isset($this->headers['location']) && $this->redirects < $redirects) + { + $this->redirects++; + $location = SimplePie_Misc::absolutize_url($this->headers['location'], $url); + return $this->SimplePie_File($location, $timeout, $redirects, $headers, $useragent, $force_fsockopen); + } + if (isset($this->headers['content-encoding'])) + { + // Hey, we act dumb elsewhere, so let's do that here too + switch(strtolower(trim($this->headers['content-encoding'], "\x09\x0A\x0D\x20"))) + { + case 'gzip': + case 'x-gzip': + $decoder = new SimplePie_gzdecode($this->body); + if (!$decoder->parse()) + { + $this->error = 'Unable to decode HTTP "gzip" stream'; + $this->success = false; + } + else + { + $this->body = $decoder->data; + } + break; + + case 'deflate': + if (($body = gzuncompress($this->body)) === false) + { + if (($body = gzinflate($this->body)) === false) + { + $this->error = 'Unable to decode HTTP "deflate" stream'; + $this->success = false; + } + } + $this->body = $body; + break; + + default: + $this->error = 'Unknown content coding'; + $this->success = false; + } + } + } + } + else + { + $this->error = 'fsocket timed out'; + $this->success = false; + } + fclose($fp); + } + } + } + else + { + $this->method = SIMPLEPIE_FILE_SOURCE_LOCAL | SIMPLEPIE_FILE_SOURCE_FILE_GET_CONTENTS; + if (!$this->body = file_get_contents($url)) + { + $this->error = 'file_get_contents could not read the file'; + $this->success = false; + } + } + } +} + +/** + * HTTP Response Parser + * + * @package SimplePie + */ +class SimplePie_HTTP_Parser +{ + /** + * HTTP Version + * + * @access public + * @var float + */ + var $http_version = 0.0; + + /** + * Status code + * + * @access public + * @var int + */ + var $status_code = 0; + + /** + * Reason phrase + * + * @access public + * @var string + */ + var $reason = ''; + + /** + * Key/value pairs of the headers + * + * @access public + * @var array + */ + var $headers = array(); + + /** + * Body of the response + * + * @access public + * @var string + */ + var $body = ''; + + /** + * Current state of the state machine + * + * @access private + * @var string + */ + var $state = 'http_version'; + + /** + * Input data + * + * @access private + * @var string + */ + var $data = ''; + + /** + * Input data length (to avoid calling strlen() everytime this is needed) + * + * @access private + * @var int + */ + var $data_length = 0; + + /** + * Current position of the pointer + * + * @var int + * @access private + */ + var $position = 0; + + /** + * Name of the hedaer currently being parsed + * + * @access private + * @var string + */ + var $name = ''; + + /** + * Value of the hedaer currently being parsed + * + * @access private + * @var string + */ + var $value = ''; + + /** + * Create an instance of the class with the input data + * + * @access public + * @param string $data Input data + */ + function SimplePie_HTTP_Parser($data) + { + $this->data = $data; + $this->data_length = strlen($this->data); + } + + /** + * Parse the input data + * + * @access public + * @return bool true on success, false on failure + */ + function parse() + { + while ($this->state && $this->state !== 'emit' && $this->has_data()) + { + $state = $this->state; + $this->$state(); + } + $this->data = ''; + if ($this->state === 'emit' || $this->state === 'body') + { + return true; + } + else + { + $this->http_version = ''; + $this->status_code = ''; + $this->reason = ''; + $this->headers = array(); + $this->body = ''; + return false; + } + } + + /** + * Check whether there is data beyond the pointer + * + * @access private + * @return bool true if there is further data, false if not + */ + function has_data() + { + return (bool) ($this->position < $this->data_length); + } + + /** + * See if the next character is LWS + * + * @access private + * @return bool true if the next character is LWS, false if not + */ + function is_linear_whitespace() + { + return (bool) ($this->data[$this->position] === "\x09" + || $this->data[$this->position] === "\x20" + || ($this->data[$this->position] === "\x0A" + && isset($this->data[$this->position + 1]) + && ($this->data[$this->position + 1] === "\x09" || $this->data[$this->position + 1] === "\x20"))); + } + + /** + * Parse the HTTP version + * + * @access private + */ + function http_version() + { + if (strpos($this->data, "\x0A") !== false && strtoupper(substr($this->data, 0, 5)) === 'HTTP/') + { + $len = strspn($this->data, '0123456789.', 5); + $this->http_version = substr($this->data, 5, $len); + $this->position += 5 + $len; + if (substr_count($this->http_version, '.') <= 1) + { + $this->http_version = (float) $this->http_version; + $this->position += strspn($this->data, "\x09\x20", $this->position); + $this->state = 'status'; + } + else + { + $this->state = false; + } + } + else + { + $this->state = false; + } + } + + /** + * Parse the status code + * + * @access private + */ + function status() + { + if ($len = strspn($this->data, '0123456789', $this->position)) + { + $this->status_code = (int) substr($this->data, $this->position, $len); + $this->position += $len; + $this->state = 'reason'; + } + else + { + $this->state = false; + } + } + + /** + * Parse the reason phrase + * + * @access private + */ + function reason() + { + $len = strcspn($this->data, "\x0A", $this->position); + $this->reason = trim(substr($this->data, $this->position, $len), "\x09\x0D\x20"); + $this->position += $len + 1; + $this->state = 'new_line'; + } + + /** + * Deal with a new line, shifting data around as needed + * + * @access private + */ + function new_line() + { + $this->value = trim($this->value, "\x0D\x20"); + if ($this->name !== '' && $this->value !== '') + { + $this->name = strtolower($this->name); + if (isset($this->headers[$this->name])) + { + $this->headers[$this->name] .= ', ' . $this->value; + } + else + { + $this->headers[$this->name] = $this->value; + } + } + $this->name = ''; + $this->value = ''; + if (substr($this->data[$this->position], 0, 2) === "\x0D\x0A") + { + $this->position += 2; + $this->state = 'body'; + } + elseif ($this->data[$this->position] === "\x0A") + { + $this->position++; + $this->state = 'body'; + } + else + { + $this->state = 'name'; + } + } + + /** + * Parse a header name + * + * @access private + */ + function name() + { + $len = strcspn($this->data, "\x0A:", $this->position); + if (isset($this->data[$this->position + $len])) + { + if ($this->data[$this->position + $len] === "\x0A") + { + $this->position += $len; + $this->state = 'new_line'; + } + else + { + $this->name = substr($this->data, $this->position, $len); + $this->position += $len + 1; + $this->state = 'value'; + } + } + else + { + $this->state = false; + } + } + + /** + * Parse LWS, replacing consecutive LWS characters with a single space + * + * @access private + */ + function linear_whitespace() + { + do + { + if (substr($this->data, $this->position, 2) === "\x0D\x0A") + { + $this->position += 2; + } + elseif ($this->data[$this->position] === "\x0A") + { + $this->position++; + } + $this->position += strspn($this->data, "\x09\x20", $this->position); + } while ($this->has_data() && $this->is_linear_whitespace()); + $this->value .= "\x20"; + } + + /** + * See what state to move to while within non-quoted header values + * + * @access private + */ + function value() + { + if ($this->is_linear_whitespace()) + { + $this->linear_whitespace(); + } + else + { + switch ($this->data[$this->position]) + { + case '"': + $this->position++; + $this->state = 'quote'; + break; + + case "\x0A": + $this->position++; + $this->state = 'new_line'; + break; + + default: + $this->state = 'value_char'; + break; + } + } + } + + /** + * Parse a header value while outside quotes + * + * @access private + */ + function value_char() + { + $len = strcspn($this->data, "\x09\x20\x0A\"", $this->position); + $this->value .= substr($this->data, $this->position, $len); + $this->position += $len; + $this->state = 'value'; + } + + /** + * See what state to move to while within quoted header values + * + * @access private + */ + function quote() + { + if ($this->is_linear_whitespace()) + { + $this->linear_whitespace(); + } + else + { + switch ($this->data[$this->position]) + { + case '"': + $this->position++; + $this->state = 'value'; + break; + + case "\x0A": + $this->position++; + $this->state = 'new_line'; + break; + + case '\\': + $this->position++; + $this->state = 'quote_escaped'; + break; + + default: + $this->state = 'quote_char'; + break; + } + } + } + + /** + * Parse a header value while within quotes + * + * @access private + */ + function quote_char() + { + $len = strcspn($this->data, "\x09\x20\x0A\"\\", $this->position); + $this->value .= substr($this->data, $this->position, $len); + $this->position += $len; + $this->state = 'value'; + } + + /** + * Parse an escaped character within quotes + * + * @access private + */ + function quote_escaped() + { + $this->value .= $this->data[$this->position]; + $this->position++; + $this->state = 'quote'; + } + + /** + * Parse the body + * + * @access private + */ + function body() + { + $this->body = substr($this->data, $this->position); + $this->state = 'emit'; + } +} + +/** + * gzdecode + * + * @package SimplePie + */ +class SimplePie_gzdecode +{ + /** + * Compressed data + * + * @access private + * @see gzdecode::$data + */ + var $compressed_data; + + /** + * Size of compressed data + * + * @access private + */ + var $compressed_size; + + /** + * Minimum size of a valid gzip string + * + * @access private + */ + var $min_compressed_size = 18; + + /** + * Current position of pointer + * + * @access private + */ + var $position = 0; + + /** + * Flags (FLG) + * + * @access private + */ + var $flags; + + /** + * Uncompressed data + * + * @access public + * @see gzdecode::$compressed_data + */ + var $data; + + /** + * Modified time + * + * @access public + */ + var $MTIME; + + /** + * Extra Flags + * + * @access public + */ + var $XFL; + + /** + * Operating System + * + * @access public + */ + var $OS; + + /** + * Subfield ID 1 + * + * @access public + * @see gzdecode::$extra_field + * @see gzdecode::$SI2 + */ + var $SI1; + + /** + * Subfield ID 2 + * + * @access public + * @see gzdecode::$extra_field + * @see gzdecode::$SI1 + */ + var $SI2; + + /** + * Extra field content + * + * @access public + * @see gzdecode::$SI1 + * @see gzdecode::$SI2 + */ + var $extra_field; + + /** + * Original filename + * + * @access public + */ + var $filename; + + /** + * Human readable comment + * + * @access public + */ + var $comment; + + /** + * Don't allow anything to be set + * + * @access public + */ + function __set($name, $value) + { + trigger_error("Cannot write property $name", E_USER_ERROR); + } + + /** + * Set the compressed string and related properties + * + * @access public + */ + function SimplePie_gzdecode($data) + { + $this->compressed_data = $data; + $this->compressed_size = strlen($data); + } + + /** + * Decode the GZIP stream + * + * @access public + */ + function parse() + { + if ($this->compressed_size >= $this->min_compressed_size) + { + // Check ID1, ID2, and CM + if (substr($this->compressed_data, 0, 3) !== "\x1F\x8B\x08") + { + return false; + } + + // Get the FLG (FLaGs) + $this->flags = ord($this->compressed_data[3]); + + // FLG bits above (1 << 4) are reserved + if ($flg > 0x1F) + { + return false; + } + + // Advance the pointer after the above + $this->position += 4; + + // MTIME + $mtime = substr($this->compressed_data, $this->position, 4); + // Reverse the string if we're on a big-endian arch because l is the only signed long and is machine endianness + if (current(unpack('S', "\x00\x01")) === 1) + { + $mtime = strrev($mtime); + } + $this->MTIME = current(unpack('l', $mtime)); + $this->position += 4; + + // Get the XFL (eXtra FLags) + $this->XFL = ord($this->compressed_data[$this->position++]); + + // Get the OS (Operating System) + $this->OS = ord($this->compressed_data[$this->position++]); + + // Parse the FEXTRA + if ($this->flags & 4) + { + // Read subfield IDs + $this->SI1 = $this->compressed_data[$this->position++]; + $this->SI2 = $this->compressed_data[$this->position++]; + + // SI2 set to zero is reserved for future use + if ($this->SI2 === "\x00") + { + return false; + } + + // Get the length of the extra field + $len = current(unpack('v', substr($this->compressed_data, $this->position, 2))); + $position += 2; + + // Check the length of the string is still valid + $this->min_compressed_size += $len + 4; + if ($this->compressed_size >= $this->min_compressed_size) + { + // Set the extra field to the given data + $this->extra_field = substr($this->compressed_data, $this->position, $len); + $this->position += $len; + } + else + { + return false; + } + } + + // Parse the FNAME + if ($this->flags & 8) + { + // Get the length of the filename + $len = strspn($this->compressed_data, "\x00", $this->position); + + // Check the length of the string is still valid + $this->min_compressed_size += $len + 1; + if ($this->compressed_size >= $this->min_compressed_size) + { + // Set the original filename to the given string + $this->filename = substr($this->compressed_data, $this->position, $len); + $this->position += $len + 1; + } + else + { + return false; + } + } + + // Parse the FCOMMENT + if ($this->flags & 16) + { + // Get the length of the comment + $len = strspn($this->compressed_data, "\x00", $this->position); + + // Check the length of the string is still valid + $this->min_compressed_size += $len + 1; + if ($this->compressed_size >= $this->min_compressed_size) + { + // Set the original comment to the given string + $this->comment = substr($this->compressed_data, $this->position, $len); + $this->position += $len + 1; + } + else + { + return false; + } + } + + // Parse the FHCRC + if ($this->flags & 2) + { + // Check the length of the string is still valid + $this->min_compressed_size += $len + 2; + if ($this->compressed_size >= $this->min_compressed_size) + { + // Read the CRC + $crc = current(unpack('v', substr($this->compressed_data, $this->position, 2))); + + // Check the CRC matches + if ((crc32(substr($this->compressed_data, 0, $this->position)) & 0xFFFF) === $crc) + { + $this->position += 2; + } + else + { + return false; + } + } + else + { + return false; + } + } + + // Decompress the actual data + if (($this->data = gzinflate(substr($this->compressed_data, $this->position, -8))) === false) + { + return false; + } + else + { + $this->position = $this->compressed_size - 8; + } + + // Check CRC of data + $crc = current(unpack('N', substr($this->compressed_data, $this->position, 4))); + $this->position += 4; + if (extension_loaded('hash') && hexdec(hash('crc32b', $this->data)) !== $crc) + { + return false; + } + + // Check ISIZE of data + $isize = current(unpack('N', substr($this->compressed_data, $this->position, 4))); + $this->position += 4; + if (strlen($this->data) & 0xFFFFFFFF !== $isize) + { + return false; + } + + // Wow, against all odds, we've actually got a valid gzip string + return true; + } + else + { + return false; + } + } +} + +class SimplePie_Cache +{ + /** + * Don't call the constructor. Please. + * + * @access private + */ + function SimplePie_Cache() + { + trigger_error('Please call SimplePie_Cache::create() instead of the constructor', E_USER_ERROR); + } + + /** + * Create a new SimplePie_Cache object + * + * @static + * @access public + */ + function create($location, $filename, $extension) + { + return new SimplePie_Cache_File($location, $filename, $extension); + } +} + +class SimplePie_Cache_File +{ + var $location; + var $filename; + var $extension; + var $name; + + function SimplePie_Cache_File($location, $filename, $extension) + { + $this->location = $location; + $this->filename = rawurlencode($filename); + $this->extension = rawurlencode($extension); + $this->name = "$location/$this->filename.$this->extension"; + } + + function save($data) + { + if (file_exists($this->name) && is_writeable($this->name) || file_exists($this->location) && is_writeable($this->location)) + { + if (is_a($data, 'SimplePie')) + { + $data = $data->data; + } + + $data = serialize($data); + + if (function_exists('file_put_contents')) + { + return (bool) file_put_contents($this->name, $data); + } + else + { + $fp = fopen($this->name, 'wb'); + if ($fp) + { + fwrite($fp, $data); + fclose($fp); + return true; + } + } + } + return false; + } + + function load() + { + if (file_exists($this->name) && is_readable($this->name)) + { + return unserialize(file_get_contents($this->name)); + } + return false; + } + + function mtime() + { + if (file_exists($this->name)) + { + return filemtime($this->name); + } + return false; + } + + function touch() + { + if (file_exists($this->name)) + { + return touch($this->name); + } + return false; + } + + function unlink() + { + if (file_exists($this->name)) + { + return unlink($this->name); + } + return false; + } +} + +class SimplePie_Misc +{ + function time_hms($seconds) + { + $time = ''; + + $hours = floor($seconds / 3600); + $remainder = $seconds % 3600; + if ($hours > 0) + { + $time .= $hours.':'; + } + + $minutes = floor($remainder / 60); + $seconds = $remainder % 60; + if ($minutes < 10 && $hours > 0) + { + $minutes = '0' . $minutes; + } + if ($seconds < 10) + { + $seconds = '0' . $seconds; + } + + $time .= $minutes.':'; + $time .= $seconds; + + return $time; + } + + function absolutize_url($relative, $base) + { + if ($relative !== '') + { + $relative = SimplePie_Misc::parse_url($relative); + if ($relative['scheme'] !== '') + { + $target = $relative; + } + elseif ($base !== '') + { + $base = SimplePie_Misc::parse_url($base); + $target = SimplePie_Misc::parse_url(''); + if ($relative['authority'] !== '') + { + $target = $relative; + $target['scheme'] = $base['scheme']; + } + else + { + $target['scheme'] = $base['scheme']; + $target['authority'] = $base['authority']; + if ($relative['path'] !== '') + { + if (strpos($relative['path'], '/') === 0) + { + $target['path'] = $relative['path']; + } + elseif ($base['authority'] !== '' && $base['path'] === '') + { + $target['path'] = '/' . $relative['path']; + } + elseif (($last_segment = strrpos($base['path'], '/')) !== false) + { + $target['path'] = substr($base['path'], 0, $last_segment + 1) . $relative['path']; + } + else + { + $target['path'] = $relative['path']; + } + $target['query'] = $relative['query']; + } + else + { + $target['path'] = $base['path']; + if ($relative['query'] !== '') + { + $target['query'] = $relative['query']; + } + elseif ($base['query'] !== '') + { + $target['query'] = $base['query']; + } + } + } + $target['fragment'] = $relative['fragment']; + } + else + { + // No base URL, just return the relative URL + $target = $relative; + } + $return = SimplePie_Misc::compress_parse_url($target['scheme'], $target['authority'], $target['path'], $target['query'], $target['fragment']); + } + else + { + $return = $base; + } + $return = SimplePie_Misc::normalize_url($return); + return $return; + } + + function remove_dot_segments($input) + { + $output = ''; + while (strpos($input, './') !== false || strpos($input, '/.') !== false || $input == '.' || $input == '..') + { + // A: If the input buffer begins with a prefix of "../" or "./", then remove that prefix from the input buffer; otherwise, + if (strpos($input, '../') === 0) + { + $input = substr($input, 3); + } + elseif (strpos($input, './') === 0) + { + $input = substr($input, 2); + } + // B: if the input buffer begins with a prefix of "/./" or "/.", where "." is a complete path segment, then replace that prefix with "/" in the input buffer; otherwise, + elseif (strpos($input, '/./') === 0) + { + $input = substr_replace($input, '/', 0, 3); + } + elseif ($input == '/.') + { + $input = '/'; + } + // C: if the input buffer begins with a prefix of "/../" or "/..", where ".." is a complete path segment, then replace that prefix with "/" in the input buffer and remove the last segment and its preceding "/" (if any) from the output buffer; otherwise, + elseif (strpos($input, '/../') === 0) + { + $input = substr_replace($input, '/', 0, 4); + $output = substr_replace($output, '', strrpos($output, '/')); + } + elseif ($input == '/..') + { + $input = '/'; + $output = substr_replace($output, '', strrpos($output, '/')); + } + // D: if the input buffer consists only of "." or "..", then remove that from the input buffer; otherwise, + elseif ($input == '.' || $input == '..') + { + $input = ''; + } + // E: move the first path segment in the input buffer to the end of the output buffer, including the initial "/" character (if any) and any subsequent characters up to, but not including, the next "/" character or the end of the input buffer + elseif (($pos = strpos($input, '/', 1)) !== false) + { + $output .= substr($input, 0, $pos); + $input = substr_replace($input, '', 0, $pos); + } + else + { + $output .= $input; + $input = ''; + } + } + return $output . $input; + } + + function get_element($realname, $string) + { + $return = array(); + $name = preg_quote($realname, '/'); + if (preg_match_all("/<($name)" . SIMPLEPIE_PCRE_HTML_ATTRIBUTE . "(>(.*)<\/$name>|(\/)?>)/siU", $string, $matches, PREG_SET_ORDER | PREG_OFFSET_CAPTURE)) + { + for ($i = 0, $total_matches = count($matches); $i < $total_matches; $i++) + { + $return[$i]['tag'] = $realname; + $return[$i]['full'] = $matches[$i][0][0]; + $return[$i]['offset'] = $matches[$i][0][1]; + if (strlen($matches[$i][3][0]) <= 2) + { + $return[$i]['self_closing'] = true; + } + else + { + $return[$i]['self_closing'] = false; + $return[$i]['content'] = $matches[$i][4][0]; + } + $return[$i]['attribs'] = array(); + if (isset($matches[$i][2][0]) && preg_match_all('/[\x09\x0A\x0B\x0C\x0D\x20]+([^\x09\x0A\x0B\x0C\x0D\x20\x2F\x3E][^\x09\x0A\x0B\x0C\x0D\x20\x2F\x3D\x3E]*)(?:[\x09\x0A\x0B\x0C\x0D\x20]*=[\x09\x0A\x0B\x0C\x0D\x20]*(?:"([^"]*)"|\'([^\']*)\'|([^\x09\x0A\x0B\x0C\x0D\x20\x22\x27\x3E][^\x09\x0A\x0B\x0C\x0D\x20\x3E]*)?))?/', ' ' . $matches[$i][2][0] . ' ', $attribs, PREG_SET_ORDER)) + { + for ($j = 0, $total_attribs = count($attribs); $j < $total_attribs; $j++) + { + if (count($attribs[$j]) == 2) + { + $attribs[$j][2] = $attribs[$j][1]; + } + $return[$i]['attribs'][strtolower($attribs[$j][1])]['data'] = SimplePie_Misc::entities_decode(end($attribs[$j]), 'UTF-8'); + } + } + } + } + return $return; + } + + function element_implode($element) + { + $full = "<$element[tag]"; + foreach ($element['attribs'] as $key => $value) + { + $key = strtolower($key); + $full .= " $key=\"" . htmlspecialchars($value['data']) . '"'; + } + if ($element['self_closing']) + { + $full .= ' />'; + } + else + { + $full .= ">$element[content]"; + } + return $full; + } + + function error($message, $level, $file, $line) + { + switch ($level) + { + case E_USER_ERROR: + $note = 'PHP Error'; + break; + case E_USER_WARNING: + $note = 'PHP Warning'; + break; + case E_USER_NOTICE: + $note = 'PHP Notice'; + break; + default: + $note = 'Unknown Error'; + break; + } + error_log("$note: $message in $file on line $line", 0); + return $message; + } + + /** + * If a file has been cached, retrieve and display it. + * + * This is most useful for caching images (get_favicon(), etc.), + * however it works for all cached files. This WILL NOT display ANY + * file/image/page/whatever, but rather only display what has already + * been cached by SimplePie. + * + * @access public + * @see SimplePie::get_favicon() + * @param str $identifier_url URL that is used to identify the content. + * This may or may not be the actual URL of the live content. + * @param str $cache_location Location of SimplePie's cache. Defaults + * to './cache'. + * @param str $cache_extension The file extension that the file was + * cached with. Defaults to 'spc'. + * @param str $cache_class Name of the cache-handling class being used + * in SimplePie. Defaults to 'SimplePie_Cache', and should be left + * as-is unless you've overloaded the class. + * @param str $cache_name_function Obsolete. Exists for backwards + * compatibility reasons only. + */ + function display_cached_file($identifier_url, $cache_location = './cache', $cache_extension = 'spc', $cache_class = 'SimplePie_Cache', $cache_name_function = 'md5') + { + $cache = call_user_func(array($cache_class, 'create'), $cache_location, $identifier_url, $cache_extension); + + if ($file = $cache->load()) + { + if (isset($file['headers']['content-type'])) + { + header('Content-type:' . $file['headers']['content-type']); + } + else + { + header('Content-type: application/octet-stream'); + } + header('Expires: ' . gmdate('D, d M Y H:i:s', time() + 604800) . ' GMT'); // 7 days + echo $file['body']; + exit; + } + + die('Cached file for ' . $identifier_url . ' cannot be found.'); + } + + function fix_protocol($url, $http = 1) + { + $url = SimplePie_Misc::normalize_url($url); + $parsed = SimplePie_Misc::parse_url($url); + if ($parsed['scheme'] !== '' && $parsed['scheme'] != 'http' && $parsed['scheme'] != 'https') + { + return SimplePie_Misc::fix_protocol(SimplePie_Misc::compress_parse_url('http', $parsed['authority'], $parsed['path'], $parsed['query'], $parsed['fragment']), $http); + } + + if ($parsed['scheme'] === '' && $parsed['authority'] === '' && !file_exists($url)) + { + return SimplePie_Misc::fix_protocol(SimplePie_Misc::compress_parse_url('http', $parsed['path'], '', $parsed['query'], $parsed['fragment']), $http); + } + + if ($http == 2 && $parsed['scheme'] !== '') + { + return "feed:$url"; + } + elseif ($http == 3 && strtolower($parsed['scheme']) == 'http') + { + return substr_replace($url, 'podcast', 0, 4); + } + elseif ($http == 4 && strtolower($parsed['scheme']) == 'http') + { + return substr_replace($url, 'itpc', 0, 4); + } + else + { + return $url; + } + } + + function parse_url($url) + { + static $cache = array(); + if (isset($cache[$url])) + { + return $cache[$url]; + } + elseif (preg_match('/^(([^:\/?#]+):)?(\/\/([^\/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?$/', $url, $match)) + { + for ($i = count($match); $i <= 9; $i++) + { + $match[$i] = ''; + } + return $cache[$url] = array('scheme' => $match[2], 'authority' => $match[4], 'path' => $match[5], 'query' => $match[7], 'fragment' => $match[9]); + } + else + { + return $cache[$url] = array('scheme' => '', 'authority' => '', 'path' => '', 'query' => '', 'fragment' => ''); + } + } + + function compress_parse_url($scheme = '', $authority = '', $path = '', $query = '', $fragment = '') + { + $return = ''; + if ($scheme !== '') + { + $return .= "$scheme:"; + } + if ($authority !== '') + { + $return .= "//$authority"; + } + if ($path !== '') + { + $return .= $path; + } + if ($query !== '') + { + $return .= "?$query"; + } + if ($fragment !== '') + { + $return .= "#$fragment"; + } + return $return; + } + + function normalize_url($url) + { + $url = preg_replace_callback('/%([0-9A-Fa-f]{2})/', array('SimplePie_Misc', 'percent_encoding_normalization'), $url); + $url = SimplePie_Misc::parse_url($url); + $url['scheme'] = strtolower($url['scheme']); + if ($url['authority'] !== '') + { + $url['authority'] = strtolower($url['authority']); + $url['path'] = SimplePie_Misc::remove_dot_segments($url['path']); + } + return SimplePie_Misc::compress_parse_url($url['scheme'], $url['authority'], $url['path'], $url['query'], $url['fragment']); + } + + function percent_encoding_normalization($match) + { + $integer = hexdec($match[1]); + if ($integer >= 0x41 && $integer <= 0x5A || $integer >= 0x61 && $integer <= 0x7A || $integer >= 0x30 && $integer <= 0x39 || $integer == 0x2D || $integer == 0x2E || $integer == 0x5F || $integer == 0x7E) + { + return chr($integer); + } + else + { + return strtoupper($match[0]); + } + } + + /** + * Remove bad UTF-8 bytes + * + * PCRE Pattern to locate bad bytes in a UTF-8 string comes from W3C + * FAQ: Multilingual Forms (modified to include full ASCII range) + * + * @author Geoffrey Sneddon + * @see http://www.w3.org/International/questions/qa-forms-utf-8 + * @param string $str String to remove bad UTF-8 bytes from + * @return string UTF-8 string + */ + function utf8_bad_replace($str) + { + if (function_exists('iconv') && ($return = @iconv('UTF-8', 'UTF-8//IGNORE', $str))) + { + return $return; + } + elseif (function_exists('mb_convert_encoding') && ($return = @mb_convert_encoding($str, 'UTF-8', 'UTF-8'))) + { + return $return; + } + elseif (preg_match_all('/(?:[\x00-\x7F]|[\xC2-\xDF][\x80-\xBF]|\xE0[\xA0-\xBF][\x80-\xBF]|[\xE1-\xEC\xEE\xEF][\x80-\xBF]{2}|\xED[\x80-\x9F][\x80-\xBF]|\xF0[\x90-\xBF][\x80-\xBF]{2}|[\xF1-\xF3][\x80-\xBF]{3}|\xF4[\x80-\x8F][\x80-\xBF]{2})+/', $str, $matches)) + { + return implode("\xEF\xBF\xBD", $matches[0]); + } + elseif ($str !== '') + { + return "\xEF\xBF\xBD"; + } + else + { + return ''; + } + } + + /** + * Converts a Windows-1252 encoded string to a UTF-8 encoded string + * + * @static + * @access public + * @param string $string Windows-1252 encoded string + * @return string UTF-8 encoded string + */ + function windows_1252_to_utf8($string) + { + static $convert_table = array("\x80" => "\xE2\x82\xAC", "\x81" => "\xEF\xBF\xBD", "\x82" => "\xE2\x80\x9A", "\x83" => "\xC6\x92", "\x84" => "\xE2\x80\x9E", "\x85" => "\xE2\x80\xA6", "\x86" => "\xE2\x80\xA0", "\x87" => "\xE2\x80\xA1", "\x88" => "\xCB\x86", "\x89" => "\xE2\x80\xB0", "\x8A" => "\xC5\xA0", "\x8B" => "\xE2\x80\xB9", "\x8C" => "\xC5\x92", "\x8D" => "\xEF\xBF\xBD", "\x8E" => "\xC5\xBD", "\x8F" => "\xEF\xBF\xBD", "\x90" => "\xEF\xBF\xBD", "\x91" => "\xE2\x80\x98", "\x92" => "\xE2\x80\x99", "\x93" => "\xE2\x80\x9C", "\x94" => "\xE2\x80\x9D", "\x95" => "\xE2\x80\xA2", "\x96" => "\xE2\x80\x93", "\x97" => "\xE2\x80\x94", "\x98" => "\xCB\x9C", "\x99" => "\xE2\x84\xA2", "\x9A" => "\xC5\xA1", "\x9B" => "\xE2\x80\xBA", "\x9C" => "\xC5\x93", "\x9D" => "\xEF\xBF\xBD", "\x9E" => "\xC5\xBE", "\x9F" => "\xC5\xB8", "\xA0" => "\xC2\xA0", "\xA1" => "\xC2\xA1", "\xA2" => "\xC2\xA2", "\xA3" => "\xC2\xA3", "\xA4" => "\xC2\xA4", "\xA5" => "\xC2\xA5", "\xA6" => "\xC2\xA6", "\xA7" => "\xC2\xA7", "\xA8" => "\xC2\xA8", "\xA9" => "\xC2\xA9", "\xAA" => "\xC2\xAA", "\xAB" => "\xC2\xAB", "\xAC" => "\xC2\xAC", "\xAD" => "\xC2\xAD", "\xAE" => "\xC2\xAE", "\xAF" => "\xC2\xAF", "\xB0" => "\xC2\xB0", "\xB1" => "\xC2\xB1", "\xB2" => "\xC2\xB2", "\xB3" => "\xC2\xB3", "\xB4" => "\xC2\xB4", "\xB5" => "\xC2\xB5", "\xB6" => "\xC2\xB6", "\xB7" => "\xC2\xB7", "\xB8" => "\xC2\xB8", "\xB9" => "\xC2\xB9", "\xBA" => "\xC2\xBA", "\xBB" => "\xC2\xBB", "\xBC" => "\xC2\xBC", "\xBD" => "\xC2\xBD", "\xBE" => "\xC2\xBE", "\xBF" => "\xC2\xBF", "\xC0" => "\xC3\x80", "\xC1" => "\xC3\x81", "\xC2" => "\xC3\x82", "\xC3" => "\xC3\x83", "\xC4" => "\xC3\x84", "\xC5" => "\xC3\x85", "\xC6" => "\xC3\x86", "\xC7" => "\xC3\x87", "\xC8" => "\xC3\x88", "\xC9" => "\xC3\x89", "\xCA" => "\xC3\x8A", "\xCB" => "\xC3\x8B", "\xCC" => "\xC3\x8C", "\xCD" => "\xC3\x8D", "\xCE" => "\xC3\x8E", "\xCF" => "\xC3\x8F", "\xD0" => "\xC3\x90", "\xD1" => "\xC3\x91", "\xD2" => "\xC3\x92", "\xD3" => "\xC3\x93", "\xD4" => "\xC3\x94", "\xD5" => "\xC3\x95", "\xD6" => "\xC3\x96", "\xD7" => "\xC3\x97", "\xD8" => "\xC3\x98", "\xD9" => "\xC3\x99", "\xDA" => "\xC3\x9A", "\xDB" => "\xC3\x9B", "\xDC" => "\xC3\x9C", "\xDD" => "\xC3\x9D", "\xDE" => "\xC3\x9E", "\xDF" => "\xC3\x9F", "\xE0" => "\xC3\xA0", "\xE1" => "\xC3\xA1", "\xE2" => "\xC3\xA2", "\xE3" => "\xC3\xA3", "\xE4" => "\xC3\xA4", "\xE5" => "\xC3\xA5", "\xE6" => "\xC3\xA6", "\xE7" => "\xC3\xA7", "\xE8" => "\xC3\xA8", "\xE9" => "\xC3\xA9", "\xEA" => "\xC3\xAA", "\xEB" => "\xC3\xAB", "\xEC" => "\xC3\xAC", "\xED" => "\xC3\xAD", "\xEE" => "\xC3\xAE", "\xEF" => "\xC3\xAF", "\xF0" => "\xC3\xB0", "\xF1" => "\xC3\xB1", "\xF2" => "\xC3\xB2", "\xF3" => "\xC3\xB3", "\xF4" => "\xC3\xB4", "\xF5" => "\xC3\xB5", "\xF6" => "\xC3\xB6", "\xF7" => "\xC3\xB7", "\xF8" => "\xC3\xB8", "\xF9" => "\xC3\xB9", "\xFA" => "\xC3\xBA", "\xFB" => "\xC3\xBB", "\xFC" => "\xC3\xBC", "\xFD" => "\xC3\xBD", "\xFE" => "\xC3\xBE", "\xFF" => "\xC3\xBF"); + + return strtr($string, $convert_table); + } + + function change_encoding($data, $input, $output) + { + $input = SimplePie_Misc::encoding($input); + $output = SimplePie_Misc::encoding($output); + + // We fail to fail on non US-ASCII bytes + if ($input === 'US-ASCII') + { + static $non_ascii_octects = ''; + if (!$non_ascii_octects) + { + for ($i = 0x80; $i <= 0xFF; $i++) + { + $non_ascii_octects .= chr($i); + } + } + $data = substr($data, 0, strcspn($data, $non_ascii_octects)); + } + + // This is first, as behaviour of this is completely predictable + if ($input === 'Windows-1252' && $output === 'UTF-8') + { + return SimplePie_Misc::windows_1252_to_utf8($data); + } + // This is second, as behaviour of this varies only with PHP version + elseif (function_exists('mb_convert_encoding') && ($return = @mb_convert_encoding($data, $output, $input))) + { + return $return; + } + // This is last, as behaviour of this varies with OS userland and PHP version + elseif (function_exists('iconv') && ($return = @iconv($input, $output, $data))) + { + return $return; + } + // If we can't do anything, just fail + else + { + return false; + } + } + + function encoding($charset) + { + /* Character sets are case-insensitive, and also need some further + normalization in the real world (though we'll return them in the form given + in their registration). */ + switch (strtolower(preg_replace('/[\x09-\x0D\x20-\x2F\x3A-\x40\x5B-\x60\x7B-\x7E]/', '', $charset))) + { + case 'adobestandardencoding': + case 'csadobestandardencoding': + return 'Adobe-Standard-Encoding'; + + case 'adobesymbolencoding': + case 'cshppsmath': + return 'Adobe-Symbol-Encoding'; + + case 'ami1251': + case 'ami1251': + case 'amiga1251': + case 'amiga1251': + return 'Amiga-1251'; + + case 'ansix31101983': + case 'csat5001983': + case 'csiso99naplps': + case 'isoir99': + case 'naplps': + return 'ANSI_X3.110-1983'; + + case 'arabic7': + case 'asmo449': + case 'csiso89asmo449': + case 'isoir89': + case 'iso9036': + return 'ASMO_449'; + + case 'big5': + case 'csbig5': + case 'xxbig5': + return 'Big5'; + + case 'big5hkscs': + return 'Big5-HKSCS'; + + case 'bocu1': + case 'csbocu1': + return 'BOCU-1'; + + case 'brf': + case 'csbrf': + return 'BRF'; + + case 'bs4730': + case 'csiso4unitedkingdom': + case 'gb': + case 'isoir4': + case 'iso646gb': + case 'uk': + return 'BS_4730'; + + case 'bsviewdata': + case 'csiso47bsviewdata': + case 'isoir47': + return 'BS_viewdata'; + + case 'cesu8': + case 'cscesu8': + return 'CESU-8'; + + case 'ca': + case 'csa71': + case 'csaz243419851': + case 'csiso121canadian1': + case 'isoir121': + case 'iso646ca': + return 'CSA_Z243.4-1985-1'; + + case 'csa72': + case 'csaz243419852': + case 'csiso122canadian2': + case 'isoir122': + case 'iso646ca2': + return 'CSA_Z243.4-1985-2'; + + case 'csaz24341985gr': + case 'csiso123csaz24341985gr': + case 'isoir123': + return 'CSA_Z243.4-1985-gr'; + + case 'csiso139csn369103': + case 'csn369103': + case 'isoir139': + return 'CSN_369103'; + + case 'csdecmcs': + case 'dec': + case 'decmcs': + return 'DEC-MCS'; + + case 'csiso21german': + case 'de': + case 'din66003': + case 'isoir21': + case 'iso646de': + return 'DIN_66003'; + + case 'csdkus': + case 'dkus': + return 'dk-us'; + + case 'csiso646danish': + case 'dk': + case 'ds2089': + case 'ds2089': + case 'iso646dk': + return 'DS_2089'; + + case 'csibmebcdicatde': + case 'ebcdicatde': + return 'EBCDIC-AT-DE'; + + case 'csebcdicatdea': + case 'ebcdicatdea': + return 'EBCDIC-AT-DE-A'; + + case 'csebcdiccafr': + case 'ebcdiccafr': + return 'EBCDIC-CA-FR'; + + case 'csebcdicdkno': + case 'ebcdicdkno': + return 'EBCDIC-DK-NO'; + + case 'csebcdicdknoa': + case 'ebcdicdknoa': + return 'EBCDIC-DK-NO-A'; + + case 'csebcdices': + case 'ebcdices': + return 'EBCDIC-ES'; + + case 'csebcdicesa': + case 'ebcdicesa': + return 'EBCDIC-ES-A'; + + case 'csebcdicess': + case 'ebcdicess': + return 'EBCDIC-ES-S'; + + case 'csebcdicfise': + case 'ebcdicfise': + return 'EBCDIC-FI-SE'; + + case 'csebcdicfisea': + case 'ebcdicfisea': + return 'EBCDIC-FI-SE-A'; + + case 'csebcdicfr': + case 'ebcdicfr': + return 'EBCDIC-FR'; + + case 'csebcdicit': + case 'ebcdicit': + return 'EBCDIC-IT'; + + case 'csebcdicpt': + case 'ebcdicpt': + return 'EBCDIC-PT'; + + case 'csebcdicuk': + case 'ebcdicuk': + return 'EBCDIC-UK'; + + case 'csebcdicus': + case 'ebcdicus': + return 'EBCDIC-US'; + + case 'csiso111ecmacyrillic': + case 'ecmacyrillic': + case 'isoir111': + case 'koi8e': + return 'ECMA-cyrillic'; + + case 'csiso17spanish': + case 'es': + case 'isoir17': + case 'iso646es': + return 'ES'; + + case 'csiso85spanish2': + case 'es2': + case 'isoir85': + case 'iso646es2': + return 'ES2'; + + case 'cseucfixwidjapanese': + case 'extendedunixcodefixedwidthforjapanese': + return 'Extended_UNIX_Code_Fixed_Width_for_Japanese'; + + case 'cseucpkdfmtjapanese': + case 'eucjp': + case 'extendedunixcodepackedformatforjapanese': + return 'Extended_UNIX_Code_Packed_Format_for_Japanese'; + + case 'gb18030': + return 'GB18030'; + + case 'cp936': + case 'gbk': + case 'ms936': + case 'windows936': + case 'csgb2312': + case 'gb2312': + case 'chinese': + case 'csiso58gb231280': + case 'gb231280': + case 'isoir58': + return 'GBK'; + + case 'cn': + case 'csiso57gb1988': + case 'gb198880': + case 'isoir57': + case 'iso646cn': + return 'GB_1988-80'; + + case 'csiso153gost1976874': + case 'gost1976874': + case 'isoir153': + case 'stsev35888': + return 'GOST_19768-74'; + + case 'csiso150': + case 'csiso150greekccitt': + case 'greekccitt': + case 'isoir150': + return 'greek-ccitt'; + + case 'csiso88greek7': + case 'greek7': + case 'isoir88': + return 'greek7'; + + case 'csiso18greek7old': + case 'greek7old': + case 'isoir18': + return 'greek7-old'; + + case 'cshpdesktop': + case 'hpdesktop': + return 'HP-DeskTop'; + + case 'cshplegal': + case 'hplegal': + return 'HP-Legal'; + + case 'cshpmath8': + case 'hpmath8': + return 'HP-Math8'; + + case 'cshppifont': + case 'hppifont': + return 'HP-Pi-font'; + + case 'cshproman8': + case 'hproman8': + case 'r8': + case 'roman8': + return 'hp-roman8'; + + case 'hzgb2312': + return 'HZ-GB-2312'; + + case 'csibmsymbols': + case 'ibmsymbols': + return 'IBM-Symbols'; + + case 'csibmthai': + case 'ibmthai': + return 'IBM-Thai'; + + case 'ccsid00858': + case 'cp00858': + case 'ibm00858': + case 'pcmultilingual850euro': + return 'IBM00858'; + + case 'ccsid00924': + case 'cp00924': + case 'ebcdiclatin9euro': + case 'ibm00924': + return 'IBM00924'; + + case 'ccsid01140': + case 'cp01140': + case 'ebcdicus37euro': + case 'ibm01140': + return 'IBM01140'; + + case 'ccsid01141': + case 'cp01141': + case 'ebcdicde273euro': + case 'ibm01141': + return 'IBM01141'; + + case 'ccsid01142': + case 'cp01142': + case 'ebcdicdk277euro': + case 'ebcdicno277euro': + case 'ibm01142': + return 'IBM01142'; + + case 'ccsid01143': + case 'cp01143': + case 'ebcdicfi278euro': + case 'ebcdicse278euro': + case 'ibm01143': + return 'IBM01143'; + + case 'ccsid01144': + case 'cp01144': + case 'ebcdicit280euro': + case 'ibm01144': + return 'IBM01144'; + + case 'ccsid01145': + case 'cp01145': + case 'ebcdices284euro': + case 'ibm01145': + return 'IBM01145'; + + case 'ccsid01146': + case 'cp01146': + case 'ebcdicgb285euro': + case 'ibm01146': + return 'IBM01146'; + + case 'ccsid01147': + case 'cp01147': + case 'ebcdicfr297euro': + case 'ibm01147': + return 'IBM01147'; + + case 'ccsid01148': + case 'cp01148': + case 'ebcdicinternational500euro': + case 'ibm01148': + return 'IBM01148'; + + case 'ccsid01149': + case 'cp01149': + case 'ebcdicis871euro': + case 'ibm01149': + return 'IBM01149'; + + case 'cp037': + case 'csibm037': + case 'ebcdiccpca': + case 'ebcdiccpnl': + case 'ebcdiccpus': + case 'ebcdiccpwt': + case 'ibm037': + return 'IBM037'; + + case 'cp038': + case 'csibm038': + case 'ebcdicint': + case 'ibm038': + return 'IBM038'; + + case 'cp273': + case 'csibm273': + case 'ibm273': + return 'IBM273'; + + case 'cp274': + case 'csibm274': + case 'ebcdicbe': + case 'ibm274': + return 'IBM274'; + + case 'cp275': + case 'csibm275': + case 'ebcdicbr': + case 'ibm275': + return 'IBM275'; + + case 'csibm277': + case 'ebcdiccpdk': + case 'ebcdiccpno': + case 'ibm277': + return 'IBM277'; + + case 'cp278': + case 'csibm278': + case 'ebcdiccpfi': + case 'ebcdiccpse': + case 'ibm278': + return 'IBM278'; + + case 'cp280': + case 'csibm280': + case 'ebcdiccpit': + case 'ibm280': + return 'IBM280'; + + case 'cp281': + case 'csibm281': + case 'ebcdicjpe': + case 'ibm281': + return 'IBM281'; + + case 'cp284': + case 'csibm284': + case 'ebcdiccpes': + case 'ibm284': + return 'IBM284'; + + case 'cp285': + case 'csibm285': + case 'ebcdiccpgb': + case 'ibm285': + return 'IBM285'; + + case 'cp290': + case 'csibm290': + case 'ebcdicjpkana': + case 'ibm290': + return 'IBM290'; + + case 'cp297': + case 'csibm297': + case 'ebcdiccpfr': + case 'ibm297': + return 'IBM297'; + + case 'cp420': + case 'csibm420': + case 'ebcdiccpar1': + case 'ibm420': + return 'IBM420'; + + case 'cp423': + case 'csibm423': + case 'ebcdiccpgr': + case 'ibm423': + return 'IBM423'; + + case 'cp424': + case 'csibm424': + case 'ebcdiccphe': + case 'ibm424': + return 'IBM424'; + + case '437': + case 'cp437': + case 'cspc8codepage437': + case 'ibm437': + return 'IBM437'; + + case 'cp500': + case 'csibm500': + case 'ebcdiccpbe': + case 'ebcdiccpch': + case 'ibm500': + return 'IBM500'; + + case 'cp775': + case 'cspc775baltic': + case 'ibm775': + return 'IBM775'; + + case '850': + case 'cp850': + case 'cspc850multilingual': + case 'ibm850': + return 'IBM850'; + + case '851': + case 'cp851': + case 'csibm851': + case 'ibm851': + return 'IBM851'; + + case '852': + case 'cp852': + case 'cspcp852': + case 'ibm852': + return 'IBM852'; + + case '855': + case 'cp855': + case 'csibm855': + case 'ibm855': + return 'IBM855'; + + case '857': + case 'cp857': + case 'csibm857': + case 'ibm857': + return 'IBM857'; + + case '860': + case 'cp860': + case 'csibm860': + case 'ibm860': + return 'IBM860'; + + case '861': + case 'cpis': + case 'cp861': + case 'csibm861': + case 'ibm861': + return 'IBM861'; + + case '862': + case 'cp862': + case 'cspc862latinhebrew': + case 'ibm862': + return 'IBM862'; + + case '863': + case 'cp863': + case 'csibm863': + case 'ibm863': + return 'IBM863'; + + case 'cp864': + case 'csibm864': + case 'ibm864': + return 'IBM864'; + + case '865': + case 'cp865': + case 'csibm865': + case 'ibm865': + return 'IBM865'; + + case '866': + case 'cp866': + case 'csibm866': + case 'ibm866': + return 'IBM866'; + + case 'cpar': + case 'cp868': + case 'csibm868': + case 'ibm868': + return 'IBM868'; + + case '869': + case 'cpgr': + case 'cp869': + case 'csibm869': + case 'ibm869': + return 'IBM869'; + + case 'cp870': + case 'csibm870': + case 'ebcdiccproece': + case 'ebcdiccpyu': + case 'ibm870': + return 'IBM870'; + + case 'cp871': + case 'csibm871': + case 'ebcdiccpis': + case 'ibm871': + return 'IBM871'; + + case 'cp880': + case 'csibm880': + case 'ebcdiccyrillic': + case 'ibm880': + return 'IBM880'; + + case 'cp891': + case 'csibm891': + case 'ibm891': + return 'IBM891'; + + case 'cp903': + case 'csibm903': + case 'ibm903': + return 'IBM903'; + + case '904': + case 'cp904': + case 'csibbm904': + case 'ibm904': + return 'IBM904'; + + case 'cp905': + case 'csibm905': + case 'ebcdiccptr': + case 'ibm905': + return 'IBM905'; + + case 'cp918': + case 'csibm918': + case 'ebcdiccpar2': + case 'ibm918': + return 'IBM918'; + + case 'cp1026': + case 'csibm1026': + case 'ibm1026': + return 'IBM1026'; + + case 'ibm1047': + case 'ibm1047': + return 'IBM1047'; + + case 'csiso143iecp271': + case 'iecp271': + case 'isoir143': + return 'IEC_P27-1'; + + case 'csiso49inis': + case 'inis': + case 'isoir49': + return 'INIS'; + + case 'csiso50inis8': + case 'inis8': + case 'isoir50': + return 'INIS-8'; + + case 'csiso51iniscyrillic': + case 'iniscyrillic': + case 'isoir51': + return 'INIS-cyrillic'; + + case 'csinvariant': + case 'invariant': + return 'INVARIANT'; + + case 'iso2022cn': + return 'ISO-2022-CN'; + + case 'iso2022cnext': + return 'ISO-2022-CN-EXT'; + + case 'csiso2022jp': + case 'iso2022jp': + return 'ISO-2022-JP'; + + case 'csiso2022jp2': + case 'iso2022jp2': + return 'ISO-2022-JP-2'; + + case 'csiso2022kr': + case 'iso2022kr': + return 'ISO-2022-KR'; + + case 'cswindows30latin1': + case 'iso88591windows30latin1': + return 'ISO-8859-1-Windows-3.0-Latin-1'; + + case 'cswindows31latin1': + case 'iso88591windows31latin1': + return 'ISO-8859-1-Windows-3.1-Latin-1'; + + case 'csisolatin2': + case 'iso88592': + case 'isoir101': + case 'iso88592': + case 'iso885921987': + case 'l2': + case 'latin2': + return 'ISO-8859-2'; + + case 'cswindows31latin2': + case 'iso88592windowslatin2': + return 'ISO-8859-2-Windows-Latin-2'; + + case 'csisolatin3': + case 'iso88593': + case 'isoir109': + case 'iso88593': + case 'iso885931988': + case 'l3': + case 'latin3': + return 'ISO-8859-3'; + + case 'csisolatin4': + case 'iso88594': + case 'isoir110': + case 'iso88594': + case 'iso885941988': + case 'l4': + case 'latin4': + return 'ISO-8859-4'; + + case 'csisolatincyrillic': + case 'cyrillic': + case 'iso88595': + case 'isoir144': + case 'iso88595': + case 'iso885951988': + return 'ISO-8859-5'; + + case 'arabic': + case 'asmo708': + case 'csisolatinarabic': + case 'ecma114': + case 'iso88596': + case 'isoir127': + case 'iso88596': + case 'iso885961987': + return 'ISO-8859-6'; + + case 'csiso88596e': + case 'iso88596e': + case 'iso88596e': + return 'ISO-8859-6-E'; + + case 'csiso88596i': + case 'iso88596i': + case 'iso88596i': + return 'ISO-8859-6-I'; + + case 'csisolatingreek': + case 'ecma118': + case 'elot928': + case 'greek': + case 'greek8': + case 'iso88597': + case 'isoir126': + case 'iso88597': + case 'iso885971987': + return 'ISO-8859-7'; + + case 'csisolatinhebrew': + case 'hebrew': + case 'iso88598': + case 'isoir138': + case 'iso88598': + case 'iso885981988': + return 'ISO-8859-8'; + + case 'csiso88598e': + case 'iso88598e': + case 'iso88598e': + return 'ISO-8859-8-E'; + + case 'csiso88598i': + case 'iso88598i': + case 'iso88598i': + return 'ISO-8859-8-I'; + + case 'cswindows31latin5': + case 'iso88599windowslatin5': + return 'ISO-8859-9-Windows-Latin-5'; + + case 'csisolatin6': + case 'iso885910': + case 'isoir157': + case 'iso8859101992': + case 'l6': + case 'latin6': + return 'ISO-8859-10'; + + case 'iso885913': + return 'ISO-8859-13'; + + case 'iso885914': + case 'isoceltic': + case 'isoir199': + case 'iso885914': + case 'iso8859141998': + case 'l8': + case 'latin8': + return 'ISO-8859-14'; + + case 'iso885915': + case 'iso885915': + case 'latin9': + return 'ISO-8859-15'; + + case 'iso885916': + case 'isoir226': + case 'iso885916': + case 'iso8859162001': + case 'l10': + case 'latin10': + return 'ISO-8859-16'; + + case 'iso10646j1': + return 'ISO-10646-J-1'; + + case 'csunicode': + case 'iso10646ucs2': + return 'ISO-10646-UCS-2'; + + case 'csucs4': + case 'iso10646ucs4': + return 'ISO-10646-UCS-4'; + + case 'csunicodeascii': + case 'iso10646ucsbasic': + return 'ISO-10646-UCS-Basic'; + + case 'csunicodelatin1': + case 'iso10646': + case 'iso10646unicodelatin1': + return 'ISO-10646-Unicode-Latin1'; + + case 'csiso10646utf1': + case 'iso10646utf1': + return 'ISO-10646-UTF-1'; + + case 'csiso115481': + case 'iso115481': + case 'iso115481': + case 'isotr115481': + return 'ISO-11548-1'; + + case 'csiso90': + case 'isoir90': + return 'iso-ir-90'; + + case 'csunicodeibm1261': + case 'isounicodeibm1261': + return 'ISO-Unicode-IBM-1261'; + + case 'csunicodeibm1264': + case 'isounicodeibm1264': + return 'ISO-Unicode-IBM-1264'; + + case 'csunicodeibm1265': + case 'isounicodeibm1265': + return 'ISO-Unicode-IBM-1265'; + + case 'csunicodeibm1268': + case 'isounicodeibm1268': + return 'ISO-Unicode-IBM-1268'; + + case 'csunicodeibm1276': + case 'isounicodeibm1276': + return 'ISO-Unicode-IBM-1276'; + + case 'csiso646basic1983': + case 'iso646basic1983': + case 'ref': + return 'ISO_646.basic:1983'; + + case 'csiso2intlrefversion': + case 'irv': + case 'isoir2': + case 'iso646irv1983': + return 'ISO_646.irv:1983'; + + case 'csiso2033': + case 'e13b': + case 'isoir98': + case 'iso20331983': + return 'ISO_2033-1983'; + + case 'csiso5427cyrillic': + case 'isoir37': + case 'iso5427': + return 'ISO_5427'; + + case 'isoir54': + case 'iso5427cyrillic1981': + case 'iso54271981': + return 'ISO_5427:1981'; + + case 'csiso5428greek': + case 'isoir55': + case 'iso54281980': + return 'ISO_5428:1980'; + + case 'csiso6937add': + case 'isoir152': + case 'iso6937225': + return 'ISO_6937-2-25'; + + case 'csisotextcomm': + case 'isoir142': + case 'iso69372add': + return 'ISO_6937-2-add'; + + case 'csiso8859supp': + case 'isoir154': + case 'iso8859supp': + case 'latin125': + return 'ISO_8859-supp'; + + case 'csiso10367box': + case 'isoir155': + case 'iso10367box': + return 'ISO_10367-box'; + + case 'csiso15italian': + case 'isoir15': + case 'iso646it': + case 'it': + return 'IT'; + + case 'csiso13jisc6220jp': + case 'isoir13': + case 'jisc62201969': + case 'jisc62201969jp': + case 'katakana': + case 'x02017': + return 'JIS_C6220-1969-jp'; + + case 'csiso14jisc6220ro': + case 'isoir14': + case 'iso646jp': + case 'jisc62201969ro': + case 'jp': + return 'JIS_C6220-1969-ro'; + + case 'csiso42jisc62261978': + case 'isoir42': + case 'jisc62261978': + return 'JIS_C6226-1978'; + + case 'csiso87jisx0208': + case 'isoir87': + case 'jisc62261983': + case 'jisx02081983': + case 'x0208': + return 'JIS_C6226-1983'; + + case 'csiso91jisc62291984a': + case 'isoir91': + case 'jisc62291984a': + case 'jpocra': + return 'JIS_C6229-1984-a'; + + case 'csiso92jisc62991984b': + case 'isoir92': + case 'iso646jpocrb': + case 'jisc62291984b': + case 'jpocrb': + return 'JIS_C6229-1984-b'; + + case 'csiso93jis62291984badd': + case 'isoir93': + case 'jisc62291984badd': + case 'jpocrbadd': + return 'JIS_C6229-1984-b-add'; + + case 'csiso94jis62291984hand': + case 'isoir94': + case 'jisc62291984hand': + case 'jpocrhand': + return 'JIS_C6229-1984-hand'; + + case 'csiso95jis62291984handadd': + case 'isoir95': + case 'jisc62291984handadd': + case 'jpocrhandadd': + return 'JIS_C6229-1984-hand-add'; + + case 'csiso96jisc62291984kana': + case 'isoir96': + case 'jisc62291984kana': + return 'JIS_C6229-1984-kana'; + + case 'csjisencoding': + case 'jisencoding': + return 'JIS_Encoding'; + + case 'cshalfwidthkatakana': + case 'jisx0201': + case 'x0201': + return 'JIS_X0201'; + + case 'csiso159jisx02121990': + case 'isoir159': + case 'jisx02121990': + case 'x0212': + return 'JIS_X0212-1990'; + + case 'csiso141jusib1002': + case 'isoir141': + case 'iso646yu': + case 'js': + case 'jusib1002': + case 'yu': + return 'JUS_I.B1.002'; + + case 'csiso147macedonian': + case 'isoir147': + case 'jusib1003mac': + case 'macedonian': + return 'JUS_I.B1.003-mac'; + + case 'csiso146serbian': + case 'isoir146': + case 'jusib1003serb': + case 'serbian': + return 'JUS_I.B1.003-serb'; + + case 'koi7switched': + return 'KOI7-switched'; + + case 'cskoi8r': + case 'koi8r': + return 'KOI8-R'; + + case 'koi8u': + return 'KOI8-U'; + + case 'csksc5636': + case 'iso646kr': + case 'ksc5636': + return 'KSC5636'; + + case 'cskz1048': + case 'kz1048': + case 'rk1048': + case 'strk10482002': + return 'KZ-1048'; + + case 'csiso19latingreek': + case 'isoir19': + case 'latingreek': + return 'latin-greek'; + + case 'csiso27latingreek1': + case 'isoir27': + case 'latingreek1': + return 'Latin-greek-1'; + + case 'csiso158lap': + case 'isoir158': + case 'lap': + case 'latinlap': + return 'latin-lap'; + + case 'csmacintosh': + case 'mac': + case 'macintosh': + return 'macintosh'; + + case 'csmicrosoftpublishing': + case 'microsoftpublishing': + return 'Microsoft-Publishing'; + + case 'csmnem': + case 'mnem': + return 'MNEM'; + + case 'csmnemonic': + case 'mnemonic': + return 'MNEMONIC'; + + case 'csiso86hungarian': + case 'hu': + case 'isoir86': + case 'iso646hu': + case 'msz77953': + return 'MSZ_7795.3'; + + case 'csnatsdano': + case 'isoir91': + case 'natsdano': + return 'NATS-DANO'; + + case 'csnatsdanoadd': + case 'isoir92': + case 'natsdanoadd': + return 'NATS-DANO-ADD'; + + case 'csnatssefi': + case 'isoir81': + case 'natssefi': + return 'NATS-SEFI'; + + case 'csnatssefiadd': + case 'isoir82': + case 'natssefiadd': + return 'NATS-SEFI-ADD'; + + case 'csiso151cuba': + case 'cuba': + case 'isoir151': + case 'iso646cu': + case 'ncnc001081': + return 'NC_NC00-10:81'; + + case 'csiso69french': + case 'fr': + case 'isoir69': + case 'iso646fr': + case 'nfz62010': + return 'NF_Z_62-010'; + + case 'csiso25french': + case 'isoir25': + case 'iso646fr1': + case 'nfz620101973': + return 'NF_Z_62-010_(1973)'; + + case 'csiso60danishnorwegian': + case 'csiso60norwegian1': + case 'isoir60': + case 'iso646no': + case 'no': + case 'ns45511': + return 'NS_4551-1'; + + case 'csiso61norwegian2': + case 'isoir61': + case 'iso646no2': + case 'no2': + case 'ns45512': + return 'NS_4551-2'; + + case 'osdebcdicdf03irv': + return 'OSD_EBCDIC_DF03_IRV'; + + case 'osdebcdicdf041': + return 'OSD_EBCDIC_DF04_1'; + + case 'osdebcdicdf0415': + return 'OSD_EBCDIC_DF04_15'; + + case 'cspc8danishnorwegian': + case 'pc8danishnorwegian': + return 'PC8-Danish-Norwegian'; + + case 'cspc8turkish': + case 'pc8turkish': + return 'PC8-Turkish'; + + case 'csiso16portuguese': + case 'isoir16': + case 'iso646pt': + case 'pt': + return 'PT'; + + case 'csiso84portuguese2': + case 'isoir84': + case 'iso646pt2': + case 'pt2': + return 'PT2'; + + case 'cp154': + case 'csptcp154': + case 'cyrillicasian': + case 'pt154': + case 'ptcp154': + return 'PTCP154'; + + case 'scsu': + return 'SCSU'; + + case 'csiso10swedish': + case 'fi': + case 'isoir10': + case 'iso646fi': + case 'iso646se': + case 'se': + case 'sen850200b': + return 'SEN_850200_B'; + + case 'csiso11swedishfornames': + case 'isoir11': + case 'iso646se2': + case 'se2': + case 'sen850200c': + return 'SEN_850200_C'; + + case 'csshiftjis': + case 'mskanji': + case 'shiftjis': + return 'Shift_JIS'; + + case 'csiso102t617bit': + case 'isoir102': + case 't617bit': + return 'T.61-7bit'; + + case 'csiso103t618bit': + case 'isoir103': + case 't61': + case 't618bit': + return 'T.61-8bit'; + + case 'csiso128t101g2': + case 'isoir128': + case 't101g2': + return 'T.101-G2'; + + case 'cstscii': + case 'tscii': + return 'TSCII'; + + case 'csunicode11': + case 'unicode11': + return 'UNICODE-1-1'; + + case 'csunicode11utf7': + case 'unicode11utf7': + return 'UNICODE-1-1-UTF-7'; + + case 'csunknown8bit': + case 'unknown8bit': + return 'UNKNOWN-8BIT'; + + case 'ansix341968': + case 'ansix341986': + case 'ascii': + case 'cp367': + case 'csascii': + case 'ibm367': + case 'isoir6': + case 'iso646us': + case 'iso646irv1991': + case 'us': + case 'usascii': + return 'US-ASCII'; + + case 'csusdk': + case 'usdk': + return 'us-dk'; + + case 'utf7': + return 'UTF-7'; + + case 'utf8': + return 'UTF-8'; + + case 'utf16': + return 'UTF-16'; + + case 'utf16be': + return 'UTF-16BE'; + + case 'utf16le': + return 'UTF-16LE'; + + case 'utf32': + return 'UTF-32'; + + case 'utf32be': + return 'UTF-32BE'; + + case 'utf32le': + return 'UTF-32LE'; + + case 'csventurainternational': + case 'venturainternational': + return 'Ventura-International'; + + case 'csventuramath': + case 'venturamath': + return 'Ventura-Math'; + + case 'csventuraus': + case 'venturaus': + return 'Ventura-US'; + + case 'csiso70videotexsupp1': + case 'isoir70': + case 'videotexsuppl': + return 'videotex-suppl'; + + case 'csviqr': + case 'viqr': + return 'VIQR'; + + case 'csviscii': + case 'viscii': + return 'VISCII'; + + case 'cswindows31j': + case 'windows31j': + return 'Windows-31J'; + + case 'iso885911': + case 'tis620': + return 'Windows-874'; + + case 'cseuckr': + case 'euckr': + case 'windows949': + case 'csksc56011987': + case 'isoir149': + case 'korean': + case 'ksc5601': + case 'ksc56011987': + case 'ksc56011989': + return 'Windows-949'; + + case 'windows1250': + return 'windows-1250'; + + case 'windows1251': + return 'windows-1251'; + + case 'cp819': + case 'csisolatin1': + case 'ibm819': + case 'iso88591': + case 'isoir100': + case 'iso885911987': + case 'l1': + case 'latin1': + case 'windows1252': + return 'Windows-1252'; + + case 'windows1252': + return 'windows-1252'; + + case 'windows1253': + return 'windows-1253'; + + case 'csisolatin5': + case 'iso88599': + case 'isoir148': + case 'iso885991989': + case 'l5': + case 'latin5': + case 'windows1254': + return 'Windows-1254'; + + case 'windows1254': + return 'windows-1254'; + + case 'windows1255': + return 'windows-1255'; + + case 'windows1256': + return 'windows-1256'; + + case 'windows1257': + return 'windows-1257'; + + case 'windows1258': + return 'windows-1258'; + + default: + return $charset; + } + } + + function get_curl_version() + { + if (is_array($curl = curl_version())) + { + $curl = $curl['version']; + } + elseif (substr($curl, 0, 5) == 'curl/') + { + $curl = substr($curl, 5, strcspn($curl, "\x09\x0A\x0B\x0C\x0D", 5)); + } + elseif (substr($curl, 0, 8) == 'libcurl/') + { + $curl = substr($curl, 8, strcspn($curl, "\x09\x0A\x0B\x0C\x0D", 8)); + } + else + { + $curl = 0; + } + return $curl; + } + + function is_subclass_of($class1, $class2) + { + if (func_num_args() != 2) + { + trigger_error('Wrong parameter count for SimplePie_Misc::is_subclass_of()', E_USER_WARNING); + } + elseif (version_compare(PHP_VERSION, '5.0.3', '>=') || is_object($class1)) + { + return is_subclass_of($class1, $class2); + } + elseif (is_string($class1) && is_string($class2)) + { + if (class_exists($class1)) + { + if (class_exists($class2)) + { + $class2 = strtolower($class2); + while ($class1 = strtolower(get_parent_class($class1))) + { + if ($class1 == $class2) + { + return true; + } + } + } + } + else + { + trigger_error('Unknown class passed as parameter', E_USER_WARNNG); + } + } + return false; + } + + /** + * Strip HTML comments + * + * @access public + * @param string $data Data to strip comments from + * @return string Comment stripped string + */ + function strip_comments($data) + { + $output = ''; + while (($start = strpos($data, '', $start)) !== false) + { + $data = substr_replace($data, '', 0, $end + 3); + } + else + { + $data = ''; + } + } + return $output . $data; + } + + function parse_date($dt) + { + $parser = SimplePie_Parse_Date::get(); + return $parser->parse($dt); + } + + /** + * Decode HTML entities + * + * @static + * @access public + * @param string $data Input data + * @return string Output data + */ + function entities_decode($data) + { + $decoder = new SimplePie_Decode_HTML_Entities($data); + return $decoder->parse(); + } + + /** + * Remove RFC822 comments + * + * @access public + * @param string $data Data to strip comments from + * @return string Comment stripped string + */ + function uncomment_rfc822($string) + { + $string = (string) $string; + $position = 0; + $length = strlen($string); + $depth = 0; + + $output = ''; + + while ($position < $length && ($pos = strpos($string, '(', $position)) !== false) + { + $output .= substr($string, $position, $pos - $position); + $position = $pos + 1; + if ($string[$pos - 1] !== '\\') + { + $depth++; + while ($depth && $position < $length) + { + $position += strcspn($string, '()', $position); + if ($string[$position - 1] === '\\') + { + $position++; + continue; + } + elseif (isset($string[$position])) + { + switch ($string[$position]) + { + case '(': + $depth++; + break; + + case ')': + $depth--; + break; + } + $position++; + } + else + { + break; + } + } + } + else + { + $output .= '('; + } + } + $output .= substr($string, $position); + + return $output; + } + + function parse_mime($mime) + { + if (($pos = strpos($mime, ';')) === false) + { + return trim($mime); + } + else + { + return trim(substr($mime, 0, $pos)); + } + } + + function htmlspecialchars_decode($string, $quote_style) + { + if (function_exists('htmlspecialchars_decode')) + { + return htmlspecialchars_decode($string, $quote_style); + } + else + { + return strtr($string, array_flip(get_html_translation_table(HTML_SPECIALCHARS, $quote_style))); + } + } + + function atom_03_construct_type($attribs) + { + if (isset($attribs['']['mode']) && strtolower(trim($attribs['']['mode']) == 'base64')) + { + $mode = SIMPLEPIE_CONSTRUCT_BASE64; + } + else + { + $mode = SIMPLEPIE_CONSTRUCT_NONE; + } + if (isset($attribs['']['type'])) + { + switch (strtolower(trim($attribs['']['type']))) + { + case 'text': + case 'text/plain': + return SIMPLEPIE_CONSTRUCT_TEXT | $mode; + + case 'html': + case 'text/html': + return SIMPLEPIE_CONSTRUCT_HTML | $mode; + + case 'xhtml': + case 'application/xhtml+xml': + return SIMPLEPIE_CONSTRUCT_XHTML | $mode; + + default: + return SIMPLEPIE_CONSTRUCT_NONE | $mode; + } + } + else + { + return SIMPLEPIE_CONSTRUCT_TEXT | $mode; + } + } + + function atom_10_construct_type($attribs) + { + if (isset($attribs['']['type'])) + { + switch (strtolower(trim($attribs['']['type']))) + { + case 'text': + return SIMPLEPIE_CONSTRUCT_TEXT; + + case 'html': + return SIMPLEPIE_CONSTRUCT_HTML; + + case 'xhtml': + return SIMPLEPIE_CONSTRUCT_XHTML; + + default: + return SIMPLEPIE_CONSTRUCT_NONE; + } + } + return SIMPLEPIE_CONSTRUCT_TEXT; + } + + function atom_10_content_construct_type($attribs) + { + if (isset($attribs['']['type'])) + { + $type = strtolower(trim($attribs['']['type'])); + switch ($type) + { + case 'text': + return SIMPLEPIE_CONSTRUCT_TEXT; + + case 'html': + return SIMPLEPIE_CONSTRUCT_HTML; + + case 'xhtml': + return SIMPLEPIE_CONSTRUCT_XHTML; + } + if (in_array(substr($type, -4), array('+xml', '/xml')) || substr($type, 0, 5) == 'text/') + { + return SIMPLEPIE_CONSTRUCT_NONE; + } + else + { + return SIMPLEPIE_CONSTRUCT_BASE64; + } + } + else + { + return SIMPLEPIE_CONSTRUCT_TEXT; + } + } + + function is_isegment_nz_nc($string) + { + return (bool) preg_match('/^([A-Za-z0-9\-._~\x{A0}-\x{D7FF}\x{F900}-\x{FDCF}\x{FDF0}-\x{FFEF}\x{10000}-\x{1FFFD}\x{20000}-\x{2FFFD}\x{30000}-\x{3FFFD}\x{40000}-\x{4FFFD}\x{50000}-\x{5FFFD}\x{60000}-\x{6FFFD}\x{70000}-\x{7FFFD}\x{80000}-\x{8FFFD}\x{90000}-\x{9FFFD}\x{A0000}-\x{AFFFD}\x{B0000}-\x{BFFFD}\x{C0000}-\x{CFFFD}\x{D0000}-\x{DFFFD}\x{E1000}-\x{EFFFD}!$&\'()*+,;=@]|(%[0-9ABCDEF]{2}))+$/u', $string); + } + + function space_seperated_tokens($string) + { + $space_characters = "\x20\x09\x0A\x0B\x0C\x0D"; + $string_length = strlen($string); + + $position = strspn($string, $space_characters); + $tokens = array(); + + while ($position < $string_length) + { + $len = strcspn($string, $space_characters, $position); + $tokens[] = substr($string, $position, $len); + $position += $len; + $position += strspn($string, $space_characters, $position); + } + + return $tokens; + } + + function array_unique($array) + { + if (version_compare(PHP_VERSION, '5.2', '>=')) + { + return array_unique($array); + } + else + { + $array = (array) $array; + $new_array = array(); + $new_array_strings = array(); + foreach ($array as $key => $value) + { + if (is_object($value)) + { + if (method_exists($value, '__toString')) + { + $cmp = $value->__toString(); + } + else + { + trigger_error('Object of class ' . get_class($value) . ' could not be converted to string', E_USER_ERROR); + } + } + elseif (is_array($value)) + { + $cmp = (string) reset($value); + } + else + { + $cmp = (string) $value; + } + if (!in_array($cmp, $new_array_strings)) + { + $new_array[$key] = $value; + $new_array_strings[] = $cmp; + } + } + return $new_array; + } + } + + /** + * Converts a unicode codepoint to a UTF-8 character + * + * @static + * @access public + * @param int $codepoint Unicode codepoint + * @return string UTF-8 character + */ + function codepoint_to_utf8($codepoint) + { + static $cache = array(); + $codepoint = (int) $codepoint; + if (isset($cache[$codepoint])) + { + return $cache[$codepoint]; + } + elseif ($codepoint < 0) + { + return $cache[$codepoint] = false; + } + else if ($codepoint <= 0x7f) + { + return $cache[$codepoint] = chr($codepoint); + } + else if ($codepoint <= 0x7ff) + { + return $cache[$codepoint] = chr(0xc0 | ($codepoint >> 6)) . chr(0x80 | ($codepoint & 0x3f)); + } + else if ($codepoint <= 0xffff) + { + return $cache[$codepoint] = chr(0xe0 | ($codepoint >> 12)) . chr(0x80 | (($codepoint >> 6) & 0x3f)) . chr(0x80 | ($codepoint & 0x3f)); + } + else if ($codepoint <= 0x10ffff) + { + return $cache[$codepoint] = chr(0xf0 | ($codepoint >> 18)) . chr(0x80 | (($codepoint >> 12) & 0x3f)) . chr(0x80 | (($codepoint >> 6) & 0x3f)) . chr(0x80 | ($codepoint & 0x3f)); + } + else + { + // U+FFFD REPLACEMENT CHARACTER + return $cache[$codepoint] = "\xEF\xBF\xBD"; + } + } + + /** + * Re-implementation of PHP 5's stripos() + * + * Returns the numeric position of the first occurrence of needle in the + * haystack string. + * + * @static + * @access string + * @param object $haystack + * @param string $needle Note that the needle may be a string of one or more + * characters. If needle is not a string, it is converted to an integer + * and applied as the ordinal value of a character. + * @param int $offset The optional offset parameter allows you to specify which + * character in haystack to start searching. The position returned is still + * relative to the beginning of haystack. + * @return bool If needle is not found, stripos() will return boolean false. + */ + function stripos($haystack, $needle, $offset = 0) + { + if (function_exists('stripos')) + { + return stripos($haystack, $needle, $offset); + } + else + { + if (is_string($needle)) + { + $needle = strtolower($needle); + } + elseif (is_int($needle) || is_bool($needle) || is_double($needle)) + { + $needle = strtolower(chr($needle)); + } + else + { + trigger_error('needle is not a string or an integer', E_USER_WARNING); + return false; + } + + return strpos(strtolower($haystack), $needle, $offset); + } + } + + /** + * Similar to parse_str() + * + * Returns an associative array of name/value pairs, where the value is an + * array of values that have used the same name + * + * @static + * @access string + * @param string $str The input string. + * @return array + */ + function parse_str($str) + { + $return = array(); + $str = explode('&', $str); + + foreach ($str as $section) + { + if (strpos($section, '=') !== false) + { + list($name, $value) = explode('=', $section, 2); + $return[urldecode($name)][] = urldecode($value); + } + else + { + $return[urldecode($section)][] = null; + } + } + + return $return; + } + + /** + * Detect XML encoding, as per XML 1.0 Appendix F.1 + * + * @todo Add support for EBCDIC + * @param string $data XML data + * @return array Possible encodings + */ + function xml_encoding($data) + { + // UTF-32 Big Endian BOM + if (substr($data, 0, 4) === "\x00\x00\xFE\xFF") + { + $encoding[] = 'UTF-32BE'; + } + // UTF-32 Little Endian BOM + elseif (substr($data, 0, 4) === "\xFF\xFE\x00\x00") + { + $encoding[] = 'UTF-32LE'; + } + // UTF-16 Big Endian BOM + elseif (substr($data, 0, 2) === "\xFE\xFF") + { + $encoding[] = 'UTF-16BE'; + } + // UTF-16 Little Endian BOM + elseif (substr($data, 0, 2) === "\xFF\xFE") + { + $encoding[] = 'UTF-16LE'; + } + // UTF-8 BOM + elseif (substr($data, 0, 3) === "\xEF\xBB\xBF") + { + $encoding[] = 'UTF-8'; + } + // UTF-32 Big Endian Without BOM + elseif (substr($data, 0, 20) === "\x00\x00\x00\x3C\x00\x00\x00\x3F\x00\x00\x00\x78\x00\x00\x00\x6D\x00\x00\x00\x6C") + { + if ($pos = strpos($data, "\x00\x00\x00\x3F\x00\x00\x00\x3E")) + { + $parser = new SimplePie_XML_Declaration_Parser(SimplePie_Misc::change_encoding(substr($data, 20, $pos - 20), 'UTF-32BE', 'UTF-8')); + if ($parser->parse()) + { + $encoding[] = $parser->encoding; + } + } + $encoding[] = 'UTF-32BE'; + } + // UTF-32 Little Endian Without BOM + elseif (substr($data, 0, 20) === "\x3C\x00\x00\x00\x3F\x00\x00\x00\x78\x00\x00\x00\x6D\x00\x00\x00\x6C\x00\x00\x00") + { + if ($pos = strpos($data, "\x3F\x00\x00\x00\x3E\x00\x00\x00")) + { + $parser = new SimplePie_XML_Declaration_Parser(SimplePie_Misc::change_encoding(substr($data, 20, $pos - 20), 'UTF-32LE', 'UTF-8')); + if ($parser->parse()) + { + $encoding[] = $parser->encoding; + } + } + $encoding[] = 'UTF-32LE'; + } + // UTF-16 Big Endian Without BOM + elseif (substr($data, 0, 10) === "\x00\x3C\x00\x3F\x00\x78\x00\x6D\x00\x6C") + { + if ($pos = strpos($data, "\x00\x3F\x00\x3E")) + { + $parser = new SimplePie_XML_Declaration_Parser(SimplePie_Misc::change_encoding(substr($data, 20, $pos - 10), 'UTF-16BE', 'UTF-8')); + if ($parser->parse()) + { + $encoding[] = $parser->encoding; + } + } + $encoding[] = 'UTF-16BE'; + } + // UTF-16 Little Endian Without BOM + elseif (substr($data, 0, 10) === "\x3C\x00\x3F\x00\x78\x00\x6D\x00\x6C\x00") + { + if ($pos = strpos($data, "\x3F\x00\x3E\x00")) + { + $parser = new SimplePie_XML_Declaration_Parser(SimplePie_Misc::change_encoding(substr($data, 20, $pos - 10), 'UTF-16LE', 'UTF-8')); + if ($parser->parse()) + { + $encoding[] = $parser->encoding; + } + } + $encoding[] = 'UTF-16LE'; + } + // US-ASCII (or superset) + elseif (substr($data, 0, 5) === "\x3C\x3F\x78\x6D\x6C") + { + if ($pos = strpos($data, "\x3F\x3E")) + { + $parser = new SimplePie_XML_Declaration_Parser(substr($data, 5, $pos - 5)); + if ($parser->parse()) + { + $encoding[] = $parser->encoding; + } + } + $encoding[] = 'UTF-8'; + } + // Fallback to UTF-8 + else + { + $encoding[] = 'UTF-8'; + } + return $encoding; + } +} + +/** + * Decode HTML Entities + * + * This implements HTML5 as of revision 967 (2007-06-28) + * + * @package SimplePie + */ +class SimplePie_Decode_HTML_Entities +{ + /** + * Data to be parsed + * + * @access private + * @var string + */ + var $data = ''; + + /** + * Currently consumed bytes + * + * @access private + * @var string + */ + var $consumed = ''; + + /** + * Position of the current byte being parsed + * + * @access private + * @var int + */ + var $position = 0; + + /** + * Create an instance of the class with the input data + * + * @access public + * @param string $data Input data + */ + function SimplePie_Decode_HTML_Entities($data) + { + $this->data = $data; + } + + /** + * Parse the input data + * + * @access public + * @return string Output data + */ + function parse() + { + while (($this->position = strpos($this->data, '&', $this->position)) !== false) + { + $this->consume(); + $this->entity(); + $this->consumed = ''; + } + return $this->data; + } + + /** + * Consume the next byte + * + * @access private + * @return mixed The next byte, or false, if there is no more data + */ + function consume() + { + if (isset($this->data[$this->position])) + { + $this->consumed .= $this->data[$this->position]; + return $this->data[$this->position++]; + } + else + { + $this->consumed = false; + return false; + } + } + + /** + * Consume a range of characters + * + * @access private + * @param string $chars Characters to consume + * @return mixed A series of characters that match the range, or false + */ + function consume_range($chars) + { + if ($len = strspn($this->data, $chars, $this->position)) + { + $data = substr($this->data, $this->position, $len); + $this->consumed .= $data; + $this->position += $len; + return $data; + } + else + { + $this->consumed = false; + return false; + } + } + + /** + * Unconsume one byte + * + * @access private + */ + function unconsume() + { + $this->consumed = substr($this->consumed, 0, -1); + $this->position--; + } + + /** + * Decode an entity + * + * @access private + */ + function entity() + { + switch ($this->consume()) + { + case "\x09": + case "\x0A": + case "\x0B": + case "\x0B": + case "\x0C": + case "\x20": + case "\x3C": + case "\x26": + case false: + break; + + case "\x23": + switch ($this->consume()) + { + case "\x78": + case "\x58": + $range = '0123456789ABCDEFabcdef'; + $hex = true; + break; + + default: + $range = '0123456789'; + $hex = false; + $this->unconsume(); + break; + } + + if ($codepoint = $this->consume_range($range)) + { + static $windows_1252_specials = array(0x0D => "\x0A", 0x80 => "\xE2\x82\xAC", 0x81 => "\xEF\xBF\xBD", 0x82 => "\xE2\x80\x9A", 0x83 => "\xC6\x92", 0x84 => "\xE2\x80\x9E", 0x85 => "\xE2\x80\xA6", 0x86 => "\xE2\x80\xA0", 0x87 => "\xE2\x80\xA1", 0x88 => "\xCB\x86", 0x89 => "\xE2\x80\xB0", 0x8A => "\xC5\xA0", 0x8B => "\xE2\x80\xB9", 0x8C => "\xC5\x92", 0x8D => "\xEF\xBF\xBD", 0x8E => "\xC5\xBD", 0x8F => "\xEF\xBF\xBD", 0x90 => "\xEF\xBF\xBD", 0x91 => "\xE2\x80\x98", 0x92 => "\xE2\x80\x99", 0x93 => "\xE2\x80\x9C", 0x94 => "\xE2\x80\x9D", 0x95 => "\xE2\x80\xA2", 0x96 => "\xE2\x80\x93", 0x97 => "\xE2\x80\x94", 0x98 => "\xCB\x9C", 0x99 => "\xE2\x84\xA2", 0x9A => "\xC5\xA1", 0x9B => "\xE2\x80\xBA", 0x9C => "\xC5\x93", 0x9D => "\xEF\xBF\xBD", 0x9E => "\xC5\xBE", 0x9F => "\xC5\xB8"); + + if ($hex) + { + $codepoint = hexdec($codepoint); + } + else + { + $codepoint = intval($codepoint); + } + + if (isset($windows_1252_specials[$codepoint])) + { + $replacement = $windows_1252_specials[$codepoint]; + } + else + { + $replacement = SimplePie_Misc::codepoint_to_utf8($codepoint); + } + + if ($this->consume() != ';') + { + $this->unconsume(); + } + + $consumed_length = strlen($this->consumed); + $this->data = substr_replace($this->data, $replacement, $this->position - $consumed_length, $consumed_length); + $this->position += strlen($replacement) - $consumed_length; + } + break; + + default: + static $entities = array('Aacute' => "\xC3\x81", 'aacute' => "\xC3\xA1", 'Aacute;' => "\xC3\x81", 'aacute;' => "\xC3\xA1", 'Acirc' => "\xC3\x82", 'acirc' => "\xC3\xA2", 'Acirc;' => "\xC3\x82", 'acirc;' => "\xC3\xA2", 'acute' => "\xC2\xB4", 'acute;' => "\xC2\xB4", 'AElig' => "\xC3\x86", 'aelig' => "\xC3\xA6", 'AElig;' => "\xC3\x86", 'aelig;' => "\xC3\xA6", 'Agrave' => "\xC3\x80", 'agrave' => "\xC3\xA0", 'Agrave;' => "\xC3\x80", 'agrave;' => "\xC3\xA0", 'alefsym;' => "\xE2\x84\xB5", 'Alpha;' => "\xCE\x91", 'alpha;' => "\xCE\xB1", 'AMP' => "\x26", 'amp' => "\x26", 'AMP;' => "\x26", 'amp;' => "\x26", 'and;' => "\xE2\x88\xA7", 'ang;' => "\xE2\x88\xA0", 'apos;' => "\x27", 'Aring' => "\xC3\x85", 'aring' => "\xC3\xA5", 'Aring;' => "\xC3\x85", 'aring;' => "\xC3\xA5", 'asymp;' => "\xE2\x89\x88", 'Atilde' => "\xC3\x83", 'atilde' => "\xC3\xA3", 'Atilde;' => "\xC3\x83", 'atilde;' => "\xC3\xA3", 'Auml' => "\xC3\x84", 'auml' => "\xC3\xA4", 'Auml;' => "\xC3\x84", 'auml;' => "\xC3\xA4", 'bdquo;' => "\xE2\x80\x9E", 'Beta;' => "\xCE\x92", 'beta;' => "\xCE\xB2", 'brvbar' => "\xC2\xA6", 'brvbar;' => "\xC2\xA6", 'bull;' => "\xE2\x80\xA2", 'cap;' => "\xE2\x88\xA9", 'Ccedil' => "\xC3\x87", 'ccedil' => "\xC3\xA7", 'Ccedil;' => "\xC3\x87", 'ccedil;' => "\xC3\xA7", 'cedil' => "\xC2\xB8", 'cedil;' => "\xC2\xB8", 'cent' => "\xC2\xA2", 'cent;' => "\xC2\xA2", 'Chi;' => "\xCE\xA7", 'chi;' => "\xCF\x87", 'circ;' => "\xCB\x86", 'clubs;' => "\xE2\x99\xA3", 'cong;' => "\xE2\x89\x85", 'COPY' => "\xC2\xA9", 'copy' => "\xC2\xA9", 'COPY;' => "\xC2\xA9", 'copy;' => "\xC2\xA9", 'crarr;' => "\xE2\x86\xB5", 'cup;' => "\xE2\x88\xAA", 'curren' => "\xC2\xA4", 'curren;' => "\xC2\xA4", 'Dagger;' => "\xE2\x80\xA1", 'dagger;' => "\xE2\x80\xA0", 'dArr;' => "\xE2\x87\x93", 'darr;' => "\xE2\x86\x93", 'deg' => "\xC2\xB0", 'deg;' => "\xC2\xB0", 'Delta;' => "\xCE\x94", 'delta;' => "\xCE\xB4", 'diams;' => "\xE2\x99\xA6", 'divide' => "\xC3\xB7", 'divide;' => "\xC3\xB7", 'Eacute' => "\xC3\x89", 'eacute' => "\xC3\xA9", 'Eacute;' => "\xC3\x89", 'eacute;' => "\xC3\xA9", 'Ecirc' => "\xC3\x8A", 'ecirc' => "\xC3\xAA", 'Ecirc;' => "\xC3\x8A", 'ecirc;' => "\xC3\xAA", 'Egrave' => "\xC3\x88", 'egrave' => "\xC3\xA8", 'Egrave;' => "\xC3\x88", 'egrave;' => "\xC3\xA8", 'empty;' => "\xE2\x88\x85", 'emsp;' => "\xE2\x80\x83", 'ensp;' => "\xE2\x80\x82", 'Epsilon;' => "\xCE\x95", 'epsilon;' => "\xCE\xB5", 'equiv;' => "\xE2\x89\xA1", 'Eta;' => "\xCE\x97", 'eta;' => "\xCE\xB7", 'ETH' => "\xC3\x90", 'eth' => "\xC3\xB0", 'ETH;' => "\xC3\x90", 'eth;' => "\xC3\xB0", 'Euml' => "\xC3\x8B", 'euml' => "\xC3\xAB", 'Euml;' => "\xC3\x8B", 'euml;' => "\xC3\xAB", 'euro;' => "\xE2\x82\xAC", 'exist;' => "\xE2\x88\x83", 'fnof;' => "\xC6\x92", 'forall;' => "\xE2\x88\x80", 'frac12' => "\xC2\xBD", 'frac12;' => "\xC2\xBD", 'frac14' => "\xC2\xBC", 'frac14;' => "\xC2\xBC", 'frac34' => "\xC2\xBE", 'frac34;' => "\xC2\xBE", 'frasl;' => "\xE2\x81\x84", 'Gamma;' => "\xCE\x93", 'gamma;' => "\xCE\xB3", 'ge;' => "\xE2\x89\xA5", 'GT' => "\x3E", 'gt' => "\x3E", 'GT;' => "\x3E", 'gt;' => "\x3E", 'hArr;' => "\xE2\x87\x94", 'harr;' => "\xE2\x86\x94", 'hearts;' => "\xE2\x99\xA5", 'hellip;' => "\xE2\x80\xA6", 'Iacute' => "\xC3\x8D", 'iacute' => "\xC3\xAD", 'Iacute;' => "\xC3\x8D", 'iacute;' => "\xC3\xAD", 'Icirc' => "\xC3\x8E", 'icirc' => "\xC3\xAE", 'Icirc;' => "\xC3\x8E", 'icirc;' => "\xC3\xAE", 'iexcl' => "\xC2\xA1", 'iexcl;' => "\xC2\xA1", 'Igrave' => "\xC3\x8C", 'igrave' => "\xC3\xAC", 'Igrave;' => "\xC3\x8C", 'igrave;' => "\xC3\xAC", 'image;' => "\xE2\x84\x91", 'infin;' => "\xE2\x88\x9E", 'int;' => "\xE2\x88\xAB", 'Iota;' => "\xCE\x99", 'iota;' => "\xCE\xB9", 'iquest' => "\xC2\xBF", 'iquest;' => "\xC2\xBF", 'isin;' => "\xE2\x88\x88", 'Iuml' => "\xC3\x8F", 'iuml' => "\xC3\xAF", 'Iuml;' => "\xC3\x8F", 'iuml;' => "\xC3\xAF", 'Kappa;' => "\xCE\x9A", 'kappa;' => "\xCE\xBA", 'Lambda;' => "\xCE\x9B", 'lambda;' => "\xCE\xBB", 'lang;' => "\xE3\x80\x88", 'laquo' => "\xC2\xAB", 'laquo;' => "\xC2\xAB", 'lArr;' => "\xE2\x87\x90", 'larr;' => "\xE2\x86\x90", 'lceil;' => "\xE2\x8C\x88", 'ldquo;' => "\xE2\x80\x9C", 'le;' => "\xE2\x89\xA4", 'lfloor;' => "\xE2\x8C\x8A", 'lowast;' => "\xE2\x88\x97", 'loz;' => "\xE2\x97\x8A", 'lrm;' => "\xE2\x80\x8E", 'lsaquo;' => "\xE2\x80\xB9", 'lsquo;' => "\xE2\x80\x98", 'LT' => "\x3C", 'lt' => "\x3C", 'LT;' => "\x3C", 'lt;' => "\x3C", 'macr' => "\xC2\xAF", 'macr;' => "\xC2\xAF", 'mdash;' => "\xE2\x80\x94", 'micro' => "\xC2\xB5", 'micro;' => "\xC2\xB5", 'middot' => "\xC2\xB7", 'middot;' => "\xC2\xB7", 'minus;' => "\xE2\x88\x92", 'Mu;' => "\xCE\x9C", 'mu;' => "\xCE\xBC", 'nabla;' => "\xE2\x88\x87", 'nbsp' => "\xC2\xA0", 'nbsp;' => "\xC2\xA0", 'ndash;' => "\xE2\x80\x93", 'ne;' => "\xE2\x89\xA0", 'ni;' => "\xE2\x88\x8B", 'not' => "\xC2\xAC", 'not;' => "\xC2\xAC", 'notin;' => "\xE2\x88\x89", 'nsub;' => "\xE2\x8A\x84", 'Ntilde' => "\xC3\x91", 'ntilde' => "\xC3\xB1", 'Ntilde;' => "\xC3\x91", 'ntilde;' => "\xC3\xB1", 'Nu;' => "\xCE\x9D", 'nu;' => "\xCE\xBD", 'Oacute' => "\xC3\x93", 'oacute' => "\xC3\xB3", 'Oacute;' => "\xC3\x93", 'oacute;' => "\xC3\xB3", 'Ocirc' => "\xC3\x94", 'ocirc' => "\xC3\xB4", 'Ocirc;' => "\xC3\x94", 'ocirc;' => "\xC3\xB4", 'OElig;' => "\xC5\x92", 'oelig;' => "\xC5\x93", 'Ograve' => "\xC3\x92", 'ograve' => "\xC3\xB2", 'Ograve;' => "\xC3\x92", 'ograve;' => "\xC3\xB2", 'oline;' => "\xE2\x80\xBE", 'Omega;' => "\xCE\xA9", 'omega;' => "\xCF\x89", 'Omicron;' => "\xCE\x9F", 'omicron;' => "\xCE\xBF", 'oplus;' => "\xE2\x8A\x95", 'or;' => "\xE2\x88\xA8", 'ordf' => "\xC2\xAA", 'ordf;' => "\xC2\xAA", 'ordm' => "\xC2\xBA", 'ordm;' => "\xC2\xBA", 'Oslash' => "\xC3\x98", 'oslash' => "\xC3\xB8", 'Oslash;' => "\xC3\x98", 'oslash;' => "\xC3\xB8", 'Otilde' => "\xC3\x95", 'otilde' => "\xC3\xB5", 'Otilde;' => "\xC3\x95", 'otilde;' => "\xC3\xB5", 'otimes;' => "\xE2\x8A\x97", 'Ouml' => "\xC3\x96", 'ouml' => "\xC3\xB6", 'Ouml;' => "\xC3\x96", 'ouml;' => "\xC3\xB6", 'para' => "\xC2\xB6", 'para;' => "\xC2\xB6", 'part;' => "\xE2\x88\x82", 'permil;' => "\xE2\x80\xB0", 'perp;' => "\xE2\x8A\xA5", 'Phi;' => "\xCE\xA6", 'phi;' => "\xCF\x86", 'Pi;' => "\xCE\xA0", 'pi;' => "\xCF\x80", 'piv;' => "\xCF\x96", 'plusmn' => "\xC2\xB1", 'plusmn;' => "\xC2\xB1", 'pound' => "\xC2\xA3", 'pound;' => "\xC2\xA3", 'Prime;' => "\xE2\x80\xB3", 'prime;' => "\xE2\x80\xB2", 'prod;' => "\xE2\x88\x8F", 'prop;' => "\xE2\x88\x9D", 'Psi;' => "\xCE\xA8", 'psi;' => "\xCF\x88", 'QUOT' => "\x22", 'quot' => "\x22", 'QUOT;' => "\x22", 'quot;' => "\x22", 'radic;' => "\xE2\x88\x9A", 'rang;' => "\xE3\x80\x89", 'raquo' => "\xC2\xBB", 'raquo;' => "\xC2\xBB", 'rArr;' => "\xE2\x87\x92", 'rarr;' => "\xE2\x86\x92", 'rceil;' => "\xE2\x8C\x89", 'rdquo;' => "\xE2\x80\x9D", 'real;' => "\xE2\x84\x9C", 'REG' => "\xC2\xAE", 'reg' => "\xC2\xAE", 'REG;' => "\xC2\xAE", 'reg;' => "\xC2\xAE", 'rfloor;' => "\xE2\x8C\x8B", 'Rho;' => "\xCE\xA1", 'rho;' => "\xCF\x81", 'rlm;' => "\xE2\x80\x8F", 'rsaquo;' => "\xE2\x80\xBA", 'rsquo;' => "\xE2\x80\x99", 'sbquo;' => "\xE2\x80\x9A", 'Scaron;' => "\xC5\xA0", 'scaron;' => "\xC5\xA1", 'sdot;' => "\xE2\x8B\x85", 'sect' => "\xC2\xA7", 'sect;' => "\xC2\xA7", 'shy' => "\xC2\xAD", 'shy;' => "\xC2\xAD", 'Sigma;' => "\xCE\xA3", 'sigma;' => "\xCF\x83", 'sigmaf;' => "\xCF\x82", 'sim;' => "\xE2\x88\xBC", 'spades;' => "\xE2\x99\xA0", 'sub;' => "\xE2\x8A\x82", 'sube;' => "\xE2\x8A\x86", 'sum;' => "\xE2\x88\x91", 'sup;' => "\xE2\x8A\x83", 'sup1' => "\xC2\xB9", 'sup1;' => "\xC2\xB9", 'sup2' => "\xC2\xB2", 'sup2;' => "\xC2\xB2", 'sup3' => "\xC2\xB3", 'sup3;' => "\xC2\xB3", 'supe;' => "\xE2\x8A\x87", 'szlig' => "\xC3\x9F", 'szlig;' => "\xC3\x9F", 'Tau;' => "\xCE\xA4", 'tau;' => "\xCF\x84", 'there4;' => "\xE2\x88\xB4", 'Theta;' => "\xCE\x98", 'theta;' => "\xCE\xB8", 'thetasym;' => "\xCF\x91", 'thinsp;' => "\xE2\x80\x89", 'THORN' => "\xC3\x9E", 'thorn' => "\xC3\xBE", 'THORN;' => "\xC3\x9E", 'thorn;' => "\xC3\xBE", 'tilde;' => "\xCB\x9C", 'times' => "\xC3\x97", 'times;' => "\xC3\x97", 'TRADE;' => "\xE2\x84\xA2", 'trade;' => "\xE2\x84\xA2", 'Uacute' => "\xC3\x9A", 'uacute' => "\xC3\xBA", 'Uacute;' => "\xC3\x9A", 'uacute;' => "\xC3\xBA", 'uArr;' => "\xE2\x87\x91", 'uarr;' => "\xE2\x86\x91", 'Ucirc' => "\xC3\x9B", 'ucirc' => "\xC3\xBB", 'Ucirc;' => "\xC3\x9B", 'ucirc;' => "\xC3\xBB", 'Ugrave' => "\xC3\x99", 'ugrave' => "\xC3\xB9", 'Ugrave;' => "\xC3\x99", 'ugrave;' => "\xC3\xB9", 'uml' => "\xC2\xA8", 'uml;' => "\xC2\xA8", 'upsih;' => "\xCF\x92", 'Upsilon;' => "\xCE\xA5", 'upsilon;' => "\xCF\x85", 'Uuml' => "\xC3\x9C", 'uuml' => "\xC3\xBC", 'Uuml;' => "\xC3\x9C", 'uuml;' => "\xC3\xBC", 'weierp;' => "\xE2\x84\x98", 'Xi;' => "\xCE\x9E", 'xi;' => "\xCE\xBE", 'Yacute' => "\xC3\x9D", 'yacute' => "\xC3\xBD", 'Yacute;' => "\xC3\x9D", 'yacute;' => "\xC3\xBD", 'yen' => "\xC2\xA5", 'yen;' => "\xC2\xA5", 'yuml' => "\xC3\xBF", 'Yuml;' => "\xC5\xB8", 'yuml;' => "\xC3\xBF", 'Zeta;' => "\xCE\x96", 'zeta;' => "\xCE\xB6", 'zwj;' => "\xE2\x80\x8D", 'zwnj;' => "\xE2\x80\x8C"); + + for ($i = 0, $match = null; $i < 9 && $this->consume() !== false; $i++) + { + $consumed = substr($this->consumed, 1); + if (isset($entities[$consumed])) + { + $match = $consumed; + } + } + + if ($match !== null) + { + $this->data = substr_replace($this->data, $entities[$match], $this->position - strlen($consumed) - 1, strlen($match) + 1); + $this->position += strlen($entities[$match]) - strlen($consumed) - 1; + } + break; + } + } +} + +/** + * Date Parser + * + * @package SimplePie + */ +class SimplePie_Parse_Date +{ + /** + * Input data + * + * @access protected + * @var string + */ + var $date; + + /** + * List of days, calendar day name => ordinal day number in the week + * + * @access protected + * @var array + */ + var $day = array( + // English + 'mon' => 1, + 'monday' => 1, + 'tue' => 2, + 'tuesday' => 2, + 'wed' => 3, + 'wednesday' => 3, + 'thu' => 4, + 'thursday' => 4, + 'fri' => 5, + 'friday' => 5, + 'sat' => 6, + 'saturday' => 6, + 'sun' => 7, + 'sunday' => 7, + // Dutch + 'maandag' => 1, + 'dinsdag' => 2, + 'woensdag' => 3, + 'donderdag' => 4, + 'vrijdag' => 5, + 'zaterdag' => 6, + 'zondag' => 7, + // French + 'lundi' => 1, + 'mardi' => 2, + 'mercredi' => 3, + 'jeudi' => 4, + 'vendredi' => 5, + 'samedi' => 6, + 'dimanche' => 7, + // German + 'montag' => 1, + 'dienstag' => 2, + 'mittwoch' => 3, + 'donnerstag' => 4, + 'freitag' => 5, + 'samstag' => 6, + 'sonnabend' => 6, + 'sonntag' => 7, + // Italian + 'lunedì' => 1, + 'martedì' => 2, + 'mercoledì' => 3, + 'giovedì' => 4, + 'venerdì' => 5, + 'sabato' => 6, + 'domenica' => 7, + // Spanish + 'lunes' => 1, + 'martes' => 2, + 'miércoles' => 3, + 'jueves' => 4, + 'viernes' => 5, + 'sábado' => 6, + 'domingo' => 7, + // Finnish + 'maanantai' => 1, + 'tiistai' => 2, + 'keskiviikko' => 3, + 'torstai' => 4, + 'perjantai' => 5, + 'lauantai' => 6, + 'sunnuntai' => 7, + // Hungarian + 'hétfő' => 1, + 'kedd' => 2, + 'szerda' => 3, + 'csütörtok' => 4, + 'péntek' => 5, + 'szombat' => 6, + 'vasárnap' => 7, + // Greek + 'Δευ' => 1, + 'Τρι' => 2, + 'Τετ' => 3, + 'Πεμ' => 4, + 'Παρ' => 5, + 'Σαβ' => 6, + 'Κυρ' => 7, + ); + + /** + * List of months, calendar month name => calendar month number + * + * @access protected + * @var array + */ + var $month = array( + // English + 'jan' => 1, + 'january' => 1, + 'feb' => 2, + 'february' => 2, + 'mar' => 3, + 'march' => 3, + 'apr' => 4, + 'april' => 4, + 'may' => 5, + // No long form of May + 'jun' => 6, + 'june' => 6, + 'jul' => 7, + 'july' => 7, + 'aug' => 8, + 'august' => 8, + 'sep' => 9, + 'september' => 8, + 'oct' => 10, + 'october' => 10, + 'nov' => 11, + 'november' => 11, + 'dec' => 12, + 'december' => 12, + // Dutch + 'januari' => 1, + 'februari' => 2, + 'maart' => 3, + 'april' => 4, + 'mei' => 5, + 'juni' => 6, + 'juli' => 7, + 'augustus' => 8, + 'september' => 9, + 'oktober' => 10, + 'november' => 11, + 'december' => 12, + // French + 'janvier' => 1, + 'février' => 2, + 'mars' => 3, + 'avril' => 4, + 'mai' => 5, + 'juin' => 6, + 'juillet' => 7, + 'août' => 8, + 'septembre' => 9, + 'octobre' => 10, + 'novembre' => 11, + 'décembre' => 12, + // German + 'januar' => 1, + 'februar' => 2, + 'märz' => 3, + 'april' => 4, + 'mai' => 5, + 'juni' => 6, + 'juli' => 7, + 'august' => 8, + 'september' => 9, + 'oktober' => 10, + 'november' => 11, + 'dezember' => 12, + // Italian + 'gennaio' => 1, + 'febbraio' => 2, + 'marzo' => 3, + 'aprile' => 4, + 'maggio' => 5, + 'giugno' => 6, + 'luglio' => 7, + 'agosto' => 8, + 'settembre' => 9, + 'ottobre' => 10, + 'novembre' => 11, + 'dicembre' => 12, + // Spanish + 'enero' => 1, + 'febrero' => 2, + 'marzo' => 3, + 'abril' => 4, + 'mayo' => 5, + 'junio' => 6, + 'julio' => 7, + 'agosto' => 8, + 'septiembre' => 9, + 'setiembre' => 9, + 'octubre' => 10, + 'noviembre' => 11, + 'diciembre' => 12, + // Finnish + 'tammikuu' => 1, + 'helmikuu' => 2, + 'maaliskuu' => 3, + 'huhtikuu' => 4, + 'toukokuu' => 5, + 'kesäkuu' => 6, + 'heinäkuu' => 7, + 'elokuu' => 8, + 'suuskuu' => 9, + 'lokakuu' => 10, + 'marras' => 11, + 'joulukuu' => 12, + // Hungarian + 'január' => 1, + 'február' => 2, + 'március' => 3, + 'április' => 4, + 'május' => 5, + 'június' => 6, + 'július' => 7, + 'augusztus' => 8, + 'szeptember' => 9, + 'október' => 10, + 'november' => 11, + 'december' => 12, + // Greek + 'Ιαν' => 1, + 'Φεβ' => 2, + 'Μάώ' => 3, + 'Μαώ' => 3, + 'Απρ' => 4, + 'Μάι' => 5, + 'Μαϊ' => 5, + 'Μαι' => 5, + 'Ιούν' => 6, + 'Ιον' => 6, + 'Ιούλ' => 7, + 'Ιολ' => 7, + 'Αύγ' => 8, + 'Αυγ' => 8, + 'Σεπ' => 9, + 'Οκτ' => 10, + 'Νοέ' => 11, + 'Δεκ' => 12, + ); + + /** + * List of timezones, abbreviation => offset from UTC + * + * @access protected + * @var array + */ + var $timezone = array( + 'ACDT' => 37800, + 'ACIT' => 28800, + 'ACST' => 34200, + 'ACT' => -18000, + 'ACWDT' => 35100, + 'ACWST' => 31500, + 'AEDT' => 39600, + 'AEST' => 36000, + 'AFT' => 16200, + 'AKDT' => -28800, + 'AKST' => -32400, + 'AMDT' => 18000, + 'AMT' => -14400, + 'ANAST' => 46800, + 'ANAT' => 43200, + 'ART' => -10800, + 'AZOST' => -3600, + 'AZST' => 18000, + 'AZT' => 14400, + 'BIOT' => 21600, + 'BIT' => -43200, + 'BOT' => -14400, + 'BRST' => -7200, + 'BRT' => -10800, + 'BST' => 3600, + 'BTT' => 21600, + 'CAST' => 18000, + 'CAT' => 7200, + 'CCT' => 23400, + 'CDT' => -18000, + 'CEDT' => 7200, + 'CET' => 3600, + 'CGST' => -7200, + 'CGT' => -10800, + 'CHADT' => 49500, + 'CHAST' => 45900, + 'CIST' => -28800, + 'CKT' => -36000, + 'CLDT' => -10800, + 'CLST' => -14400, + 'COT' => -18000, + 'CST' => -21600, + 'CVT' => -3600, + 'CXT' => 25200, + 'DAVT' => 25200, + 'DTAT' => 36000, + 'EADT' => -18000, + 'EAST' => -21600, + 'EAT' => 10800, + 'ECT' => -18000, + 'EDT' => -14400, + 'EEST' => 10800, + 'EET' => 7200, + 'EGT' => -3600, + 'EKST' => 21600, + 'EST' => -18000, + 'FJT' => 43200, + 'FKDT' => -10800, + 'FKST' => -14400, + 'FNT' => -7200, + 'GALT' => -21600, + 'GEDT' => 14400, + 'GEST' => 10800, + 'GFT' => -10800, + 'GILT' => 43200, + 'GIT' => -32400, + 'GST' => 14400, + 'GST' => -7200, + 'GYT' => -14400, + 'HAA' => -10800, + 'HAC' => -18000, + 'HADT' => -32400, + 'HAE' => -14400, + 'HAP' => -25200, + 'HAR' => -21600, + 'HAST' => -36000, + 'HAT' => -9000, + 'HAY' => -28800, + 'HKST' => 28800, + 'HMT' => 18000, + 'HNA' => -14400, + 'HNC' => -21600, + 'HNE' => -18000, + 'HNP' => -28800, + 'HNR' => -25200, + 'HNT' => -12600, + 'HNY' => -32400, + 'IRDT' => 16200, + 'IRKST' => 32400, + 'IRKT' => 28800, + 'IRST' => 12600, + 'JFDT' => -10800, + 'JFST' => -14400, + 'JST' => 32400, + 'KGST' => 21600, + 'KGT' => 18000, + 'KOST' => 39600, + 'KOVST' => 28800, + 'KOVT' => 25200, + 'KRAST' => 28800, + 'KRAT' => 25200, + 'KST' => 32400, + 'LHDT' => 39600, + 'LHST' => 37800, + 'LINT' => 50400, + 'LKT' => 21600, + 'MAGST' => 43200, + 'MAGT' => 39600, + 'MAWT' => 21600, + 'MDT' => -21600, + 'MESZ' => 7200, + 'MEZ' => 3600, + 'MHT' => 43200, + 'MIT' => -34200, + 'MNST' => 32400, + 'MSDT' => 14400, + 'MSST' => 10800, + 'MST' => -25200, + 'MUT' => 14400, + 'MVT' => 18000, + 'MYT' => 28800, + 'NCT' => 39600, + 'NDT' => -9000, + 'NFT' => 41400, + 'NMIT' => 36000, + 'NOVST' => 25200, + 'NOVT' => 21600, + 'NPT' => 20700, + 'NRT' => 43200, + 'NST' => -12600, + 'NUT' => -39600, + 'NZDT' => 46800, + 'NZST' => 43200, + 'OMSST' => 25200, + 'OMST' => 21600, + 'PDT' => -25200, + 'PET' => -18000, + 'PETST' => 46800, + 'PETT' => 43200, + 'PGT' => 36000, + 'PHOT' => 46800, + 'PHT' => 28800, + 'PKT' => 18000, + 'PMDT' => -7200, + 'PMST' => -10800, + 'PONT' => 39600, + 'PST' => -28800, + 'PWT' => 32400, + 'PYST' => -10800, + 'PYT' => -14400, + 'RET' => 14400, + 'ROTT' => -10800, + 'SAMST' => 18000, + 'SAMT' => 14400, + 'SAST' => 7200, + 'SBT' => 39600, + 'SCDT' => 46800, + 'SCST' => 43200, + 'SCT' => 14400, + 'SEST' => 3600, + 'SGT' => 28800, + 'SIT' => 28800, + 'SRT' => -10800, + 'SST' => -39600, + 'SYST' => 10800, + 'SYT' => 7200, + 'TFT' => 18000, + 'THAT' => -36000, + 'TJT' => 18000, + 'TKT' => -36000, + 'TMT' => 18000, + 'TOT' => 46800, + 'TPT' => 32400, + 'TRUT' => 36000, + 'TVT' => 43200, + 'TWT' => 28800, + 'UYST' => -7200, + 'UYT' => -10800, + 'UZT' => 18000, + 'VET' => -14400, + 'VLAST' => 39600, + 'VLAT' => 36000, + 'VOST' => 21600, + 'VUT' => 39600, + 'WAST' => 7200, + 'WAT' => 3600, + 'WDT' => 32400, + 'WEST' => 3600, + 'WFT' => 43200, + 'WIB' => 25200, + 'WIT' => 32400, + 'WITA' => 28800, + 'WKST' => 18000, + 'WST' => 28800, + 'YAKST' => 36000, + 'YAKT' => 32400, + 'YAPT' => 36000, + 'YEKST' => 21600, + 'YEKT' => 18000, + ); + + /** + * Cached PCRE for SimplePie_Parse_Date::$day + * + * @access protected + * @var string + */ + var $day_pcre; + + /** + * Cached PCRE for SimplePie_Parse_Date::$month + * + * @access protected + * @var string + */ + var $month_pcre; + + /** + * Array of user-added callback methods + * + * @access private + * @var array + */ + var $built_in = array(); + + /** + * Array of user-added callback methods + * + * @access private + * @var array + */ + var $user = array(); + + /** + * Create new SimplePie_Parse_Date object, and set self::day_pcre, + * self::month_pcre, and self::built_in + * + * @access private + */ + function SimplePie_Parse_Date() + { + $this->day_pcre = '(' . implode(array_keys($this->day), '|') . ')'; + $this->month_pcre = '(' . implode(array_keys($this->month), '|') . ')'; + + static $cache; + if (!isset($cache[get_class($this)])) + { + if (extension_loaded('Reflection')) + { + $class = new ReflectionClass(get_class($this)); + $methods = $class->getMethods(); + $all_methods = array(); + foreach ($methods as $method) + { + $all_methods[] = $method->getName(); + } + } + else + { + $all_methods = get_class_methods($this); + } + + foreach ($all_methods as $method) + { + if (strtolower(substr($method, 0, 5)) === 'date_') + { + $cache[get_class($this)][] = $method; + } + } + } + + foreach ($cache[get_class($this)] as $method) + { + $this->built_in[] = $method; + } + } + + /** + * Get the object + * + * @access public + */ + function get() + { + static $object; + if (!$object) + { + $object = new SimplePie_Parse_Date; + } + return $object; + } + + /** + * Parse a date + * + * @final + * @access public + * @param string $date Date to parse + * @return int Timestamp corresponding to date string, or false on failure + */ + function parse($date) + { + foreach ($this->user as $method) + { + if (($returned = call_user_func($method, $date)) !== false) + { + return $returned; + } + } + + foreach ($this->built_in as $method) + { + if (($returned = call_user_func(array(&$this, $method), $date)) !== false) + { + return $returned; + } + } + + return false; + } + + /** + * Add a callback method to parse a date + * + * @final + * @access public + * @param callback $callback + */ + function add_callback($callback) + { + if (is_callable($callback)) + { + $this->user[] = $callback; + } + else + { + trigger_error('User-supplied function must be a valid callback', E_USER_WARNING); + } + } + + /** + * Parse a superset of W3C-DTF (allows hyphens and colons to be omitted, as + * well as allowing any of upper or lower case "T", horizontal tabs, or + * spaces to be used as the time seperator (including more than one)) + * + * @access protected + * @return int Timestamp + */ + function date_w3cdtf($date) + { + static $pcre; + if (!$pcre) + { + $year = '([0-9]{4})'; + $month = $day = $hour = $minute = $second = '([0-9]{2})'; + $decimal = '([0-9]*)'; + $zone = '(?:(Z)|([+\-])([0-9]{1,2}):?([0-9]{1,2}))'; + $pcre = '/^' . $year . '(?:-?' . $month . '(?:-?' . $day . '(?:[Tt\x09\x20]+' . $hour . '(?::?' . $minute . '(?::?' . $second . '(?:.' . $decimal . ')?)?)?' . $zone . ')?)?)?$/'; + } + if (preg_match($pcre, $date, $match)) + { + /* + Capturing subpatterns: + 1: Year + 2: Month + 3: Day + 4: Hour + 5: Minute + 6: Second + 7: Decimal fraction of a second + 8: Zulu + 9: Timezone ± + 10: Timezone hours + 11: Timezone minutes + */ + + // Fill in empty matches + for ($i = count($match); $i <= 3; $i++) + { + $match[$i] = '1'; + } + + for ($i = count($match); $i <= 7; $i++) + { + $match[$i] = '0'; + } + + // Numeric timezone + if (isset($match[9]) && $match[9] !== '') + { + $timezone = $match[10] * 3600; + $timezone += $match[11] * 60; + if ($match[9] === '-') + { + $timezone = 0 - $timezone; + } + } + else + { + $timezone = 0; + } + + // Convert the number of seconds to an integer, taking decimals into account + $second = round($match[6] + $match[7] / pow(10, strlen($match[7]))); + + return gmmktime($match[4], $match[5], $second, $match[2], $match[3], $match[1]) - $timezone; + } + else + { + return false; + } + } + + /** + * Remove RFC822 comments + * + * @access protected + * @param string $data Data to strip comments from + * @return string Comment stripped string + */ + function remove_rfc2822_comments($string) + { + $string = (string) $string; + $position = 0; + $length = strlen($string); + $depth = 0; + + $output = ''; + + while ($position < $length && ($pos = strpos($string, '(', $position)) !== false) + { + $output .= substr($string, $position, $pos - $position); + $position = $pos + 1; + if ($string[$pos - 1] !== '\\') + { + $depth++; + while ($depth && $position < $length) + { + $position += strcspn($string, '()', $position); + if ($string[$position - 1] === '\\') + { + $position++; + continue; + } + elseif (isset($string[$position])) + { + switch ($string[$position]) + { + case '(': + $depth++; + break; + + case ')': + $depth--; + break; + } + $position++; + } + else + { + break; + } + } + } + else + { + $output .= '('; + } + } + $output .= substr($string, $position); + + return $output; + } + + /** + * Parse RFC2822's date format + * + * @access protected + * @return int Timestamp + */ + function date_rfc2822($date) + { + static $pcre; + if (!$pcre) + { + $wsp = '[\x09\x20]'; + $fws = '(?:' . $wsp . '+|' . $wsp . '*(?:\x0D\x0A' . $wsp . '+)+)'; + $optional_fws = $fws . '?'; + $day_name = $this->day_pcre; + $month = $this->month_pcre; + $day = '([0-9]{1,2})'; + $hour = $minute = $second = '([0-9]{2})'; + $year = '([0-9]{2,4})'; + $num_zone = '([+\-])([0-9]{2})([0-9]{2})'; + $character_zone = '([A-Z]{1,5})'; + $zone = '(?:' . $num_zone . '|' . $character_zone . ')'; + $pcre = '/(?:' . $optional_fws . $day_name . $optional_fws . ',)?' . $optional_fws . $day . $fws . $month . $fws . $year . $fws . $hour . $optional_fws . ':' . $optional_fws . $minute . '(?:' . $optional_fws . ':' . $optional_fws . $second . ')?' . $fws . $zone . '/i'; + } + if (preg_match($pcre, $this->remove_rfc2822_comments($date), $match)) + { + /* + Capturing subpatterns: + 1: Day name + 2: Day + 3: Month + 4: Year + 5: Hour + 6: Minute + 7: Second + 8: Timezone ± + 9: Timezone hours + 10: Timezone minutes + 11: Alphabetic timezone + */ + + // Find the month number + $month = $this->month[strtolower($match[3])]; + + // Numeric timezone + if ($match[8] !== '') + { + $timezone = $match[9] * 3600; + $timezone += $match[10] * 60; + if ($match[8] === '-') + { + $timezone = 0 - $timezone; + } + } + // Character timezone + elseif (isset($this->timezone[strtoupper($match[11])])) + { + $timezone = $this->timezone[strtoupper($match[11])]; + } + // Assume everything else to be -0000 + else + { + $timezone = 0; + } + + // Deal with 2/3 digit years + if ($match[4] < 50) + { + $match[4] += 2000; + } + elseif ($match[4] < 1000) + { + $match[4] += 1900; + } + + // Second is optional, if it is empty set it to zero + if ($match[7] !== '') + { + $second = $match[7]; + } + else + { + $second = 0; + } + + return gmmktime($match[5], $match[6], $second, $month, $match[2], $match[4]) - $timezone; + } + else + { + return false; + } + } + + /** + * Parse RFC850's date format + * + * @access protected + * @return int Timestamp + */ + function date_rfc850($date) + { + static $pcre; + if (!$pcre) + { + $space = '[\x09\x20]+'; + $day_name = $this->day_pcre; + $month = $this->month_pcre; + $day = '([0-9]{1,2})'; + $year = $hour = $minute = $second = '([0-9]{2})'; + $zone = '([A-Z]{1,5})'; + $pcre = '/^' . $day_name . ',' . $space . $day . '-' . $month . '-' . $year . $space . $hour . ':' . $minute . ':' . $second . $space . $zone . '$/i'; + } + if (preg_match($pcre, $date, $match)) + { + /* + Capturing subpatterns: + 1: Day name + 2: Day + 3: Month + 4: Year + 5: Hour + 6: Minute + 7: Second + 8: Timezone + */ + + // Month + $month = $this->month[strtolower($match[3])]; + + // Character timezone + if (isset($this->timezone[strtoupper($match[8])])) + { + $timezone = $this->timezone[strtoupper($match[8])]; + } + // Assume everything else to be -0000 + else + { + $timezone = 0; + } + + // Deal with 2 digit year + if ($match[4] < 50) + { + $match[4] += 2000; + } + else + { + $match[4] += 1900; + } + + return gmmktime($match[5], $match[6], $match[7], $month, $match[2], $match[4]) - $timezone; + } + else + { + return false; + } + } + + /** + * Parse C99's asctime()'s date format + * + * @access protected + * @return int Timestamp + */ + function date_asctime($date) + { + static $pcre; + if (!$pcre) + { + $space = '[\x09\x20]+'; + $wday_name = $this->day_pcre; + $mon_name = $this->month_pcre; + $day = '([0-9]{1,2})'; + $hour = $sec = $min = '([0-9]{2})'; + $year = '([0-9]{4})'; + $terminator = '\x0A?\x00?'; + $pcre = '/^' . $wday_name . $space . $mon_name . $space . $day . $space . $hour . ':' . $min . ':' . $sec . $space . $year . $terminator . '$/i'; + } + if (preg_match($pcre, $date, $match)) + { + /* + Capturing subpatterns: + 1: Day name + 2: Month + 3: Day + 4: Hour + 5: Minute + 6: Second + 7: Year + */ + + $month = $this->month[strtolower($match[2])]; + return gmmktime($match[4], $match[5], $match[6], $month, $match[3], $match[7]); + } + else + { + return false; + } + } + + /** + * Parse dates using strtotime() + * + * @access protected + * @return int Timestamp + */ + function date_strtotime($date) + { + $strtotime = strtotime($date); + if ($strtotime === -1 || $strtotime === false) + { + return false; + } + else + { + return $strtotime; + } + } +} + +/** + * Content-type sniffing + * + * @package SimplePie + */ +class SimplePie_Content_Type_Sniffer +{ + /** + * File object + * + * @var SimplePie_File + * @access private + */ + var $file; + + /** + * Create an instance of the class with the input file + * + * @access public + * @param SimplePie_Content_Type_Sniffer $file Input file + */ + function SimplePie_Content_Type_Sniffer($file) + { + $this->file = $file; + } + + /** + * Get the Content-Type of the specified file + * + * @access public + * @return string Actual Content-Type + */ + function get_type() + { + if (isset($this->file->headers['content-type'])) + { + if (!isset($this->file->headers['content-encoding']) + && ($this->file->headers['content-type'] === 'text/plain' + || $this->file->headers['content-type'] === 'text/plain; charset=ISO-8859-1' + || $this->file->headers['content-type'] === 'text/plain; charset=iso-8859-1')) + { + return $this->text_or_binary(); + } + + if (($pos = strpos($this->file->headers['content-type'], ';')) !== false) + { + $official = substr($this->file->headers['content-type'], 0, $pos); + } + else + { + $official = $this->file->headers['content-type']; + } + $official = strtolower($official); + + if ($official === 'unknown/unknown' + || $official === 'application/unknown') + { + return $this->unknown(); + } + elseif (substr($official, -4) === '+xml' + || $official === 'text/xml' + || $official === 'application/xml') + { + return $official; + } + elseif (substr($official, 0, 6) === 'image/') + { + if ($return = $this->image()) + { + return $return; + } + else + { + return $official; + } + } + elseif ($official === 'text/html') + { + return $this->feed_or_html(); + } + else + { + return $official; + } + } + else + { + return $this->unknown(); + } + } + + /** + * Sniff text or binary + * + * @access private + * @return string Actual Content-Type + */ + function text_or_binary() + { + if (substr($this->file->body, 0, 2) === "\xFE\xFF" + || substr($this->file->body, 0, 2) === "\xFF\xFE" + || substr($this->file->body, 0, 4) === "\x00\x00\xFE\xFF" + || substr($this->file->body, 0, 3) === "\xEF\xBB\xBF") + { + return 'text/plain'; + } + elseif (preg_match('/[\x00-\x08\x0E-\x1A\x1C-\x1F]/', $this->file->body)) + { + return 'application/octect-stream'; + } + else + { + return 'text/plain'; + } + } + + /** + * Sniff unknown + * + * @access private + * @return string Actual Content-Type + */ + function unknown() + { + $ws = strspn($this->file->body, "\x09\x0A\x0B\x0C\x0D\x20"); + if (strtolower(substr($this->file->body, $ws, 14)) === 'file->body, $ws, 5)) === 'file->body, $ws, 7)) === 'file->body, 0, 5) === '%PDF-') + { + return 'application/pdf'; + } + elseif (substr($this->file->body, 0, 11) === '%!PS-Adobe-') + { + return 'application/postscript'; + } + elseif (substr($this->file->body, 0, 6) === 'GIF87a' + || substr($this->file->body, 0, 6) === 'GIF89a') + { + return 'image/gif'; + } + elseif (substr($this->file->body, 0, 8) === "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A") + { + return 'image/png'; + } + elseif (substr($this->file->body, 0, 3) === "\xFF\xD8\xFF") + { + return 'image/jpeg'; + } + elseif (substr($this->file->body, 0, 2) === "\x42\x4D") + { + return 'image/bmp'; + } + else + { + return $this->text_or_binary(); + } + } + + /** + * Sniff images + * + * @access private + * @return string Actual Content-Type + */ + function image() + { + if (substr($this->file->body, 0, 6) === 'GIF87a' + || substr($this->file->body, 0, 6) === 'GIF89a') + { + return 'image/gif'; + } + elseif (substr($this->file->body, 0, 8) === "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A") + { + return 'image/png'; + } + elseif (substr($this->file->body, 0, 3) === "\xFF\xD8\xFF") + { + return 'image/jpeg'; + } + elseif (substr($this->file->body, 0, 2) === "\x42\x4D") + { + return 'image/bmp'; + } + else + { + return false; + } + } + + /** + * Sniff HTML + * + * @access private + * @return string Actual Content-Type + */ + function feed_or_html() + { + $len = strlen($this->file->body); + $pos = strspn($this->file->body, "\x09\x0A\x0D\x20"); + + while ($pos < $len) + { + switch ($this->file->body[$pos]) + { + case "\x09": + case "\x0A": + case "\x0D": + case "\x20": + $pos += strspn($this->file->body, "\x09\x0A\x0D\x20", $pos); + continue 2; + + case '<': + $pos++; + break; + + default: + return 'text/html'; + } + + if (substr($this->file->body, $pos, 3) === '!--') + { + $pos += 3; + if ($pos < $len && ($pos = strpos($this->file->body, '-->', $pos)) !== false) + { + $pos += 3; + } + else + { + return 'text/html'; + } + } + elseif (substr($this->file->body, $pos, 1) === '!') + { + if ($pos < $len && ($pos = strpos($this->file->body, '>', $pos)) !== false) + { + $pos++; + } + else + { + return 'text/html'; + } + } + elseif (substr($this->file->body, $pos, 1) === '?') + { + if ($pos < $len && ($pos = strpos($this->file->body, '?>', $pos)) !== false) + { + $pos += 2; + } + else + { + return 'text/html'; + } + } + elseif (substr($this->file->body, $pos, 3) === 'rss' + || substr($this->file->body, $pos, 7) === 'rdf:RDF') + { + return 'application/rss+xml'; + } + elseif (substr($this->file->body, $pos, 4) === 'feed') + { + return 'application/atom+xml'; + } + else + { + return 'text/html'; + } + } + + return 'text/html'; + } +} + +/** + * Parses the XML Declaration + * + * @package SimplePie + */ +class SimplePie_XML_Declaration_Parser +{ + /** + * XML Version + * + * @access public + * @var string + */ + var $version = '1.0'; + + /** + * Encoding + * + * @access public + * @var string + */ + var $encoding = 'UTF-8'; + + /** + * Standalone + * + * @access public + * @var bool + */ + var $standalone = false; + + /** + * Current state of the state machine + * + * @access private + * @var string + */ + var $state = 'before_version_name'; + + /** + * Input data + * + * @access private + * @var string + */ + var $data = ''; + + /** + * Input data length (to avoid calling strlen() everytime this is needed) + * + * @access private + * @var int + */ + var $data_length = 0; + + /** + * Current position of the pointer + * + * @var int + * @access private + */ + var $position = 0; + + /** + * Create an instance of the class with the input data + * + * @access public + * @param string $data Input data + */ + function SimplePie_XML_Declaration_Parser($data) + { + $this->data = $data; + $this->data_length = strlen($this->data); + } + + /** + * Parse the input data + * + * @access public + * @return bool true on success, false on failure + */ + function parse() + { + while ($this->state && $this->state !== 'emit' && $this->has_data()) + { + $state = $this->state; + $this->$state(); + } + $this->data = ''; + if ($this->state === 'emit') + { + return true; + } + else + { + $this->version = ''; + $this->encoding = ''; + $this->standalone = ''; + return false; + } + } + + /** + * Check whether there is data beyond the pointer + * + * @access private + * @return bool true if there is further data, false if not + */ + function has_data() + { + return (bool) ($this->position < $this->data_length); + } + + /** + * Advance past any whitespace + * + * @return int Number of whitespace characters passed + */ + function skip_whitespace() + { + $whitespace = strspn($this->data, "\x09\x0A\x0D\x20", $this->position); + $this->position += $whitespace; + return $whitespace; + } + + /** + * Read value + */ + function get_value() + { + $quote = substr($this->data, $this->position, 1); + if ($quote === '"' || $quote === "'") + { + $this->position++; + $len = strcspn($this->data, $quote, $this->position); + if ($this->has_data()) + { + $value = substr($this->data, $this->position, $len); + $this->position += $len + 1; + return $value; + } + } + return false; + } + + function before_version_name() + { + if ($this->skip_whitespace()) + { + $this->state = 'version_name'; + } + else + { + $this->state = false; + } + } + + function version_name() + { + if (substr($this->data, $this->position, 7) === 'version') + { + $this->position += 7; + $this->skip_whitespace(); + $this->state = 'version_equals'; + } + else + { + $this->state = false; + } + } + + function version_equals() + { + if (substr($this->data, $this->position, 1) === '=') + { + $this->position++; + $this->skip_whitespace(); + $this->state = 'version_value'; + } + else + { + $this->state = false; + } + } + + function version_value() + { + if ($this->version = $this->get_value()) + { + $this->skip_whitespace(); + if ($this->has_data()) + { + $this->state = 'encoding_name'; + } + else + { + $this->state = 'emit'; + } + } + else + { + $this->state = 'standalone_name'; + } + } + + function encoding_name() + { + if (substr($this->data, $this->position, 8) === 'encoding') + { + $this->position += 8; + $this->skip_whitespace(); + $this->state = 'encoding_equals'; + } + else + { + $this->state = false; + } + } + + function encoding_equals() + { + if (substr($this->data, $this->position, 1) === '=') + { + $this->position++; + $this->skip_whitespace(); + $this->state = 'encoding_value'; + } + else + { + $this->state = false; + } + } + + function encoding_value() + { + if ($this->encoding = $this->get_value()) + { + $this->skip_whitespace(); + if ($this->has_data()) + { + $this->state = 'standalone_name'; + } + else + { + $this->state = 'emit'; + } + } + else + { + $this->state = false; + } + } + + function standalone_name() + { + if (substr($this->data, $this->position, 10) === 'standalone') + { + $this->position += 10; + $this->skip_whitespace(); + $this->state = 'standalone_equals'; + } + else + { + $this->state = false; + } + } + + function standalone_equals() + { + if (substr($this->data, $this->position, 1) === '=') + { + $this->position++; + $this->skip_whitespace(); + $this->state = 'standalone_value'; + } + else + { + $this->state = false; + } + } + + function standalone_value() + { + if ($standalone = $this->get_value()) + { + switch ($standalone) + { + case 'yes': + $this->standalone = true; + break; + + case 'no': + $this->standalone = false; + break; + + default: + $this->state = false; + return; + } + + $this->skip_whitespace(); + if ($this->has_data()) + { + $this->state = false; + } + else + { + $this->state = 'emit'; + } + } + else + { + $this->state = false; + } + } +} + +class SimplePie_Locator +{ + var $useragent; + var $timeout; + var $file; + var $local = array(); + var $elsewhere = array(); + var $file_class = 'SimplePie_File'; + var $cached_entities = array(); + var $http_base; + var $base; + var $base_location = 0; + var $checked_feeds = 0; + var $max_checked_feeds = 10; + var $content_type_sniffer_class = 'SimplePie_Content_Type_Sniffer'; + + function SimplePie_Locator(&$file, $timeout = 10, $useragent = null, $file_class = 'SimplePie_File', $max_checked_feeds = 10, $content_type_sniffer_class = 'SimplePie_Content_Type_Sniffer') + { + $this->file =& $file; + $this->file_class = $file_class; + $this->useragent = $useragent; + $this->timeout = $timeout; + $this->max_checked_feeds = $max_checked_feeds; + $this->content_type_sniffer_class = $content_type_sniffer_class; + } + + function find($type = SIMPLEPIE_LOCATOR_ALL) + { + if ($this->is_feed($this->file)) + { + return $this->file; + } + + if ($this->file->method & SIMPLEPIE_FILE_SOURCE_REMOTE) + { + $sniffer = new $this->content_type_sniffer_class($this->file); + if ($sniffer->get_type() !== 'text/html') + { + return null; + } + } + + if ($type & ~SIMPLEPIE_LOCATOR_NONE) + { + $this->get_base(); + } + + if ($type & SIMPLEPIE_LOCATOR_AUTODISCOVERY && $working = $this->autodiscovery()) + { + return $working; + } + + if ($type & (SIMPLEPIE_LOCATOR_LOCAL_EXTENSION | SIMPLEPIE_LOCATOR_LOCAL_BODY | SIMPLEPIE_LOCATOR_REMOTE_EXTENSION | SIMPLEPIE_LOCATOR_REMOTE_BODY) && $this->get_links()) + { + if ($type & SIMPLEPIE_LOCATOR_LOCAL_EXTENSION && $working = $this->extension($this->local)) + { + return $working; + } + + if ($type & SIMPLEPIE_LOCATOR_LOCAL_BODY && $working = $this->body($this->local)) + { + return $working; + } + + if ($type & SIMPLEPIE_LOCATOR_REMOTE_EXTENSION && $working = $this->extension($this->elsewhere)) + { + return $working; + } + + if ($type & SIMPLEPIE_LOCATOR_REMOTE_BODY && $working = $this->body($this->elsewhere)) + { + return $working; + } + } + return null; + } + + function is_feed(&$file) + { + if ($file->method & SIMPLEPIE_FILE_SOURCE_REMOTE) + { + $sniffer = new $this->content_type_sniffer_class($file); + $sniffed = $sniffer->get_type(); + if (in_array($sniffed, array('application/rss+xml', 'application/rdf+xml', 'text/rdf', 'application/atom+xml', 'text/xml', 'application/xml'))) + { + return true; + } + else + { + return false; + } + } + elseif ($file->method & SIMPLEPIE_FILE_SOURCE_LOCAL) + { + return true; + } + else + { + return false; + } + } + + function get_base() + { + $this->http_base = $this->file->url; + $this->base = $this->http_base; + $elements = SimplePie_Misc::get_element('base', $this->file->body); + foreach ($elements as $element) + { + if ($element['attribs']['href']['data'] !== '') + { + $this->base = SimplePie_Misc::absolutize_url(trim($element['attribs']['href']['data']), $this->http_base); + $this->base_location = $element['offset']; + break; + } + } + } + + function autodiscovery() + { + $links = array_merge(SimplePie_Misc::get_element('link', $this->file->body), SimplePie_Misc::get_element('a', $this->file->body), SimplePie_Misc::get_element('area', $this->file->body)); + $done = array(); + foreach ($links as $link) + { + if ($this->checked_feeds == $this->max_checked_feeds) + { + break; + } + if (isset($link['attribs']['href']['data']) && isset($link['attribs']['rel']['data'])) + { + $rel = array_unique(SimplePie_Misc::space_seperated_tokens(strtolower($link['attribs']['rel']['data']))); + + if ($this->base_location < $link['offset']) + { + $href = SimplePie_Misc::absolutize_url(trim($link['attribs']['href']['data']), $this->base); + } + else + { + $href = SimplePie_Misc::absolutize_url(trim($link['attribs']['href']['data']), $this->http_base); + } + + if (!in_array($href, $done) && in_array('feed', $rel) || (in_array('alternate', $rel) && !empty($link['attribs']['type']['data']) && in_array(strtolower(SimplePie_Misc::parse_mime($link['attribs']['type']['data'])), array('application/rss+xml', 'application/atom+xml')))) + { + $this->checked_feeds++; + $feed =& new $this->file_class($href, $this->timeout, 5, null, $this->useragent); + if ($this->is_feed($feed)) + { + return $feed; + } + } + $done[] = $href; + } + } + return null; + } + + function get_links() + { + $links = SimplePie_Misc::get_element('a', $this->file->body); + foreach ($links as $link) + { + if (isset($link['attribs']['href']['data'])) + { + $href = trim($link['attribs']['href']['data']); + $parsed = SimplePie_Misc::parse_url($href); + if ($parsed['scheme'] === '' || preg_match('/^(http(s)|feed)?$/i', $parsed['scheme'])) + { + if ($this->base_location < $link['offset']) + { + $href = SimplePie_Misc::absolutize_url(trim($link['attribs']['href']['data']), $this->base); + } + else + { + $href = SimplePie_Misc::absolutize_url(trim($link['attribs']['href']['data']), $this->http_base); + } + + $current = SimplePie_Misc::parse_url($this->file->url); + + if ($parsed['authority'] === '' || $parsed['authority'] == $current['authority']) + { + $this->local[] = $href; + } + else + { + $this->elsewhere[] = $href; + } + } + } + } + $this->local = array_unique($this->local); + $this->elsewhere = array_unique($this->elsewhere); + if (!empty($this->local) || !empty($this->elsewhere)) + { + return true; + } + return null; + } + + function extension(&$array) + { + foreach ($array as $key => $value) + { + if ($this->checked_feeds == $this->max_checked_feeds) + { + break; + } + if (in_array(strtolower(strrchr($value, '.')), array('.rss', '.rdf', '.atom', '.xml'))) + { + $this->checked_feeds++; + $feed =& new $this->file_class($value, $this->timeout, 5, null, $this->useragent); + if ($this->is_feed($feed)) + { + return $feed; + } + else + { + unset($array[$key]); + } + } + } + return null; + } + + function body(&$array) + { + foreach ($array as $key => $value) + { + if ($this->checked_feeds == $this->max_checked_feeds) + { + break; + } + if (preg_match('/(rss|rdf|atom|xml)/i', $value)) + { + $this->checked_feeds++; + $feed =& new $this->file_class($value, $this->timeout, 5, null, $this->useragent); + if ($this->is_feed($feed)) + { + return $feed; + } + else + { + unset($array[$key]); + } + } + } + return null; + } +} + +class SimplePie_Parser +{ + var $error_code; + var $error_string; + var $current_line; + var $current_column; + var $current_byte; + var $separator = ' '; + var $feed = false; + var $namespace = array(''); + var $element = array(''); + var $xml_base = array(''); + var $xml_base_explicit = array(false); + var $xml_lang = array(''); + var $data = array(); + var $datas = array(array()); + var $current_xhtml_construct = -1; + var $encoding; + + function parse(&$data, $encoding) + { + // Use UTF-8 if we get passed US-ASCII, as every US-ASCII character is a UTF-8 character + if (strtoupper($encoding) == 'US-ASCII') + { + $this->encoding = 'UTF-8'; + } + else + { + $this->encoding = $encoding; + } + + // Strip BOM: + // UTF-32 Big Endian BOM + if (substr($data, 0, 4) === "\x00\x00\xFE\xFF") + { + $data = substr($data, 4); + } + // UTF-32 Little Endian BOM + elseif (substr($data, 0, 4) === "\xFF\xFE\x00\x00") + { + $data = substr($data, 4); + } + // UTF-16 Big Endian BOM + elseif (substr($data, 0, 2) === "\xFE\xFF") + { + $data = substr($data, 2); + } + // UTF-16 Little Endian BOM + elseif (substr($data, 0, 2) === "\xFF\xFE") + { + $data = substr($data, 2); + } + // UTF-8 BOM + elseif (substr($data, 0, 3) === "\xEF\xBB\xBF") + { + $data = substr($data, 3); + } + + if (substr($data, 0, 5) === '')) !== false) + { + $declaration = new SimplePie_XML_Declaration_Parser(substr($data, 5, $pos - 5)); + if ($declaration->parse()) + { + $data = substr($data, $pos + 2); + $data = 'version . '" encoding="' . $encoding . '" standalone="' . (($declaration->standalone) ? 'yes' : 'no') . '"?>' . $data; + } + else + { + $this->error_string = 'SimplePie bug! Please report this!'; + return false; + } + } + + // Work around libxml 2.7.0/2.7.1 bug, at least when in PHP 5.1+ + if (version_compare(PHP_VERSION, '5.1', '>=') && (LIBXML_VERSION === 20700 || LIBXML_VERSION === 20701)) + { + $data = str_replace('<', '<', $data); + $data = str_replace('>', '>', $data); + $data = str_replace('&', '&', $data); + $data = str_replace(''', ''', $data); + $data = str_replace('"', '"', $data); + } + + $return = true; + + // Create the parser + $xml = xml_parser_create_ns($this->encoding, $this->separator); + xml_parser_set_option($xml, XML_OPTION_SKIP_WHITE, 1); + xml_parser_set_option($xml, XML_OPTION_CASE_FOLDING, 0); + xml_set_object($xml, $this); + xml_set_character_data_handler($xml, 'cdata'); + xml_set_element_handler($xml, 'tag_open', 'tag_close'); + + // Parse! + if (!xml_parse($xml, $data, true)) + { + $this->error_code = xml_get_error_code($xml); + $this->error_string = xml_error_string($this->error_code); + $return = false; + } + $this->current_line = xml_get_current_line_number($xml); + $this->current_column = xml_get_current_column_number($xml); + $this->current_byte = xml_get_current_byte_index($xml); + xml_parser_free($xml); + return $return; + } + + function get_error_code() + { + return $this->error_code; + } + + function get_error_string() + { + return $this->error_string; + } + + function get_current_line() + { + return $this->current_line; + } + + function get_current_column() + { + return $this->current_column; + } + + function get_current_byte() + { + return $this->current_byte; + } + + function get_data() + { + return $this->data; + } + + function tag_open($parser, $tag, $attributes) + { + if ($this->feed === 0) + { + return; + } + elseif ($this->feed == false) + { + if (in_array($tag, array( + SIMPLEPIE_NAMESPACE_ATOM_10 . $this->separator . 'feed', + SIMPLEPIE_NAMESPACE_ATOM_03 . $this->separator . 'feed', + 'rss', + SIMPLEPIE_NAMESPACE_RDF . $this->separator . 'RDF' + ))) + { + $this->feed = 1; + } + } + else + { + $this->feed++; + } + + list($this->namespace[], $this->element[]) = $this->split_ns($tag); + + $attribs = array(); + foreach ($attributes as $name => $value) + { + list($attrib_namespace, $attribute) = $this->split_ns($name); + $attribs[$attrib_namespace][$attribute] = $value; + } + + if (isset($attribs[SIMPLEPIE_NAMESPACE_XML]['base'])) + { + $this->xml_base[] = SimplePie_Misc::absolutize_url($attribs[SIMPLEPIE_NAMESPACE_XML]['base'], end($this->xml_base)); + $this->xml_base_explicit[] = true; + } + else + { + $this->xml_base[] = end($this->xml_base); + $this->xml_base_explicit[] = end($this->xml_base_explicit); + } + + if (isset($attribs[SIMPLEPIE_NAMESPACE_XML]['lang'])) + { + $this->xml_lang[] = $attribs[SIMPLEPIE_NAMESPACE_XML]['lang']; + } + else + { + $this->xml_lang[] = end($this->xml_lang); + } + + if ($this->current_xhtml_construct >= 0) + { + $this->current_xhtml_construct++; + if (end($this->namespace) == SIMPLEPIE_NAMESPACE_XHTML) + { + $this->data['data'] .= '<' . end($this->element); + if (isset($attribs[''])) + { + foreach ($attribs[''] as $name => $value) + { + $this->data['data'] .= ' ' . $name . '="' . htmlspecialchars($value, ENT_COMPAT, $this->encoding) . '"'; + } + } + $this->data['data'] .= '>'; + } + } + else + { + $this->datas[] =& $this->data; + $this->data =& $this->data['child'][end($this->namespace)][end($this->element)][]; + $this->data = array('data' => '', 'attribs' => $attribs, 'xml_base' => end($this->xml_base), 'xml_base_explicit' => end($this->xml_base_explicit), 'xml_lang' => end($this->xml_lang)); + if ((end($this->namespace) == SIMPLEPIE_NAMESPACE_ATOM_03 && in_array(end($this->element), array('title', 'tagline', 'copyright', 'info', 'summary', 'content')) && isset($attribs['']['mode']) && $attribs['']['mode'] == 'xml') + || (end($this->namespace) == SIMPLEPIE_NAMESPACE_ATOM_10 && in_array(end($this->element), array('rights', 'subtitle', 'summary', 'info', 'title', 'content')) && isset($attribs['']['type']) && $attribs['']['type'] == 'xhtml')) + { + $this->current_xhtml_construct = 0; + } + } + } + + function cdata($parser, $cdata) + { + if ($this->current_xhtml_construct >= 0) + { + $this->data['data'] .= htmlspecialchars($cdata, ENT_QUOTES, $this->encoding); + } + elseif ($this->feed > 1) + { + $this->data['data'] .= $cdata; + } + } + + function tag_close($parser, $tag) + { + if (!$this->feed) + { + return; + } + + if ($this->current_xhtml_construct >= 0) + { + $this->current_xhtml_construct--; + if (end($this->namespace) == SIMPLEPIE_NAMESPACE_XHTML && !in_array(end($this->element), array('area', 'base', 'basefont', 'br', 'col', 'frame', 'hr', 'img', 'input', 'isindex', 'link', 'meta', 'param'))) + { + $this->data['data'] .= 'element) . '>'; + } + } + if ($this->current_xhtml_construct == -1) + { + $this->data =& $this->datas[$this->feed]; + array_pop($this->datas); + } + + array_pop($this->element); + array_pop($this->namespace); + array_pop($this->xml_base); + array_pop($this->xml_base_explicit); + array_pop($this->xml_lang); + $this->feed--; + } + + function split_ns($string) + { + static $cache = array(); + if (!isset($cache[$string])) + { + if ($pos = strpos($string, $this->separator)) + { + static $separator_length; + if (!$separator_length) + { + $separator_length = strlen($this->separator); + } + $namespace = substr($string, 0, $pos); + $local_name = substr($string, $pos + $separator_length); + if (strtolower($namespace) === SIMPLEPIE_NAMESPACE_ITUNES) + { + $namespace = SIMPLEPIE_NAMESPACE_ITUNES; + } + + // Normalize the Media RSS namespaces + if ($namespace === SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG) + { + $namespace = SIMPLEPIE_NAMESPACE_MEDIARSS; + } + $cache[$string] = array($namespace, $local_name); + } + else + { + $cache[$string] = array('', $string); + } + } + return $cache[$string]; + } +} + +/** + * @todo Move to using an actual HTML parser (this will allow tags to be properly stripped, and to switch between HTML and XHTML), this will also make it easier to shorten a string while preserving HTML tags + */ +class SimplePie_Sanitize +{ + // Private vars + var $base; + + // Options + var $remove_div = true; + var $image_handler = ''; + var $strip_htmltags = array('base', 'blink', 'body', 'doctype', 'embed', 'font', 'form', 'frame', 'frameset', 'html', 'iframe', 'input', 'marquee', 'meta', 'noscript', 'object', 'param', 'script', 'style'); + var $encode_instead_of_strip = false; + var $strip_attributes = array('bgsound', 'class', 'expr', 'id', 'style', 'onclick', 'onerror', 'onfinish', 'onmouseover', 'onmouseout', 'onfocus', 'onblur', 'lowsrc', 'dynsrc'); + var $strip_comments = false; + var $output_encoding = 'UTF-8'; + var $enable_cache = true; + var $cache_location = './cache'; + var $cache_name_function = 'md5'; + var $cache_class = 'SimplePie_Cache'; + var $file_class = 'SimplePie_File'; + var $timeout = 10; + var $useragent = ''; + var $force_fsockopen = false; + + var $replace_url_attributes = array( + 'a' => 'href', + 'area' => 'href', + 'blockquote' => 'cite', + 'del' => 'cite', + 'form' => 'action', + 'img' => array('longdesc', 'src'), + 'input' => 'src', + 'ins' => 'cite', + 'q' => 'cite' + ); + + function remove_div($enable = true) + { + $this->remove_div = (bool) $enable; + } + + function set_image_handler($page = false) + { + if ($page) + { + $this->image_handler = (string) $page; + } + else + { + $this->image_handler = false; + } + } + + function pass_cache_data($enable_cache = true, $cache_location = './cache', $cache_name_function = 'md5', $cache_class = 'SimplePie_Cache') + { + if (isset($enable_cache)) + { + $this->enable_cache = (bool) $enable_cache; + } + + if ($cache_location) + { + $this->cache_location = (string) $cache_location; + } + + if ($cache_name_function) + { + $this->cache_name_function = (string) $cache_name_function; + } + + if ($cache_class) + { + $this->cache_class = (string) $cache_class; + } + } + + function pass_file_data($file_class = 'SimplePie_File', $timeout = 10, $useragent = '', $force_fsockopen = false) + { + if ($file_class) + { + $this->file_class = (string) $file_class; + } + + if ($timeout) + { + $this->timeout = (string) $timeout; + } + + if ($useragent) + { + $this->useragent = (string) $useragent; + } + + if ($force_fsockopen) + { + $this->force_fsockopen = (string) $force_fsockopen; + } + } + + function strip_htmltags($tags = array('base', 'blink', 'body', 'doctype', 'embed', 'font', 'form', 'frame', 'frameset', 'html', 'iframe', 'input', 'marquee', 'meta', 'noscript', 'object', 'param', 'script', 'style')) + { + if ($tags) + { + if (is_array($tags)) + { + $this->strip_htmltags = $tags; + } + else + { + $this->strip_htmltags = explode(',', $tags); + } + } + else + { + $this->strip_htmltags = false; + } + } + + function encode_instead_of_strip($encode = false) + { + $this->encode_instead_of_strip = (bool) $encode; + } + + function strip_attributes($attribs = array('bgsound', 'class', 'expr', 'id', 'style', 'onclick', 'onerror', 'onfinish', 'onmouseover', 'onmouseout', 'onfocus', 'onblur', 'lowsrc', 'dynsrc')) + { + if ($attribs) + { + if (is_array($attribs)) + { + $this->strip_attributes = $attribs; + } + else + { + $this->strip_attributes = explode(',', $attribs); + } + } + else + { + $this->strip_attributes = false; + } + } + + function strip_comments($strip = false) + { + $this->strip_comments = (bool) $strip; + } + + function set_output_encoding($encoding = 'UTF-8') + { + $this->output_encoding = (string) $encoding; + } + + /** + * Set element/attribute key/value pairs of HTML attributes + * containing URLs that need to be resolved relative to the feed + * + * @access public + * @since 1.0 + * @param array $element_attribute Element/attribute key/value pairs + */ + function set_url_replacements($element_attribute = array('a' => 'href', 'area' => 'href', 'blockquote' => 'cite', 'del' => 'cite', 'form' => 'action', 'img' => array('longdesc', 'src'), 'input' => 'src', 'ins' => 'cite', 'q' => 'cite')) + { + $this->replace_url_attributes = (array) $element_attribute; + } + + function sanitize($data, $type, $base = '') + { + $data = trim($data); + if ($data !== '' || $type & SIMPLEPIE_CONSTRUCT_IRI) + { + if ($type & SIMPLEPIE_CONSTRUCT_MAYBE_HTML) + { + if (preg_match('/(&(#(x[0-9a-fA-F]+|[0-9]+)|[a-zA-Z0-9]+)|<\/[A-Za-z][^\x09\x0A\x0B\x0C\x0D\x20\x2F\x3E]*' . SIMPLEPIE_PCRE_HTML_ATTRIBUTE . '>)/', $data)) + { + $type |= SIMPLEPIE_CONSTRUCT_HTML; + } + else + { + $type |= SIMPLEPIE_CONSTRUCT_TEXT; + } + } + + if ($type & SIMPLEPIE_CONSTRUCT_BASE64) + { + $data = base64_decode($data); + } + + if ($type & SIMPLEPIE_CONSTRUCT_XHTML) + { + if ($this->remove_div) + { + $data = preg_replace('/^/', '', $data); + $data = preg_replace('/<\/div>$/', '', $data); + } + else + { + $data = preg_replace('/^/', '
', $data); + } + } + + if ($type & (SIMPLEPIE_CONSTRUCT_HTML | SIMPLEPIE_CONSTRUCT_XHTML)) + { + // Strip comments + if ($this->strip_comments) + { + $data = SimplePie_Misc::strip_comments($data); + } + + // Strip out HTML tags and attributes that might cause various security problems. + // Based on recommendations by Mark Pilgrim at: + // http://diveintomark.org/archives/2003/06/12/how_to_consume_rss_safely + if ($this->strip_htmltags) + { + foreach ($this->strip_htmltags as $tag) + { + $pcre = "/<($tag)" . SIMPLEPIE_PCRE_HTML_ATTRIBUTE . "(>(.*)<\/$tag" . SIMPLEPIE_PCRE_HTML_ATTRIBUTE . '>|(\/)?>)/siU'; + while (preg_match($pcre, $data)) + { + $data = preg_replace_callback($pcre, array(&$this, 'do_strip_htmltags'), $data); + } + } + } + + if ($this->strip_attributes) + { + foreach ($this->strip_attributes as $attrib) + { + $data = preg_replace('/(<[A-Za-z][^\x09\x0A\x0B\x0C\x0D\x20\x2F\x3E]*)' . SIMPLEPIE_PCRE_HTML_ATTRIBUTE . trim($attrib) . '(?:\s*=\s*(?:"(?:[^"]*)"|\'(?:[^\']*)\'|(?:[^\x09\x0A\x0B\x0C\x0D\x20\x22\x27\x3E][^\x09\x0A\x0B\x0C\x0D\x20\x3E]*)?))?' . SIMPLEPIE_PCRE_HTML_ATTRIBUTE . '>/', '\1\2\3>', $data); + } + } + + // Replace relative URLs + $this->base = $base; + foreach ($this->replace_url_attributes as $element => $attributes) + { + $data = $this->replace_urls($data, $element, $attributes); + } + + // If image handling (caching, etc.) is enabled, cache and rewrite all the image tags. + if (isset($this->image_handler) && ((string) $this->image_handler) !== '' && $this->enable_cache) + { + $images = SimplePie_Misc::get_element('img', $data); + foreach ($images as $img) + { + if (isset($img['attribs']['src']['data'])) + { + $image_url = call_user_func($this->cache_name_function, $img['attribs']['src']['data']); + $cache = call_user_func(array($this->cache_class, 'create'), $this->cache_location, $image_url, 'spi'); + + if ($cache->load()) + { + $img['attribs']['src']['data'] = $this->image_handler . $image_url; + $data = str_replace($img['full'], SimplePie_Misc::element_implode($img), $data); + } + else + { + $file =& new $this->file_class($img['attribs']['src']['data'], $this->timeout, 5, array('X-FORWARDED-FOR' => $_SERVER['REMOTE_ADDR']), $this->useragent, $this->force_fsockopen); + $headers = $file->headers; + + if ($file->success && ($file->status_code == 200 || ($file->status_code > 206 && $file->status_code < 300))) + { + if ($cache->save(array('headers' => $file->headers, 'body' => $file->body))) + { + $img['attribs']['src']['data'] = $this->image_handler . $image_url; + $data = str_replace($img['full'], SimplePie_Misc::element_implode($img), $data); + } + else + { + trigger_error("$cache->name is not writeable", E_USER_WARNING); + } + } + } + } + } + } + + // Having (possibly) taken stuff out, there may now be whitespace at the beginning/end of the data + $data = trim($data); + } + + if ($type & SIMPLEPIE_CONSTRUCT_IRI) + { + $data = SimplePie_Misc::absolutize_url($data, $base); + } + + if ($type & (SIMPLEPIE_CONSTRUCT_TEXT | SIMPLEPIE_CONSTRUCT_IRI)) + { + $data = htmlspecialchars($data, ENT_COMPAT, 'UTF-8'); + } + + if ($this->output_encoding != 'UTF-8') + { + $data = SimplePie_Misc::change_encoding($data, 'UTF-8', $this->output_encoding); + } + } + return $data; + } + + function replace_urls($data, $tag, $attributes) + { + if (!is_array($this->strip_htmltags) || !in_array($tag, $this->strip_htmltags)) + { + $elements = SimplePie_Misc::get_element($tag, $data); + foreach ($elements as $element) + { + if (is_array($attributes)) + { + foreach ($attributes as $attribute) + { + if (isset($element['attribs'][$attribute]['data'])) + { + $element['attribs'][$attribute]['data'] = SimplePie_Misc::absolutize_url($element['attribs'][$attribute]['data'], $this->base); + $new_element = SimplePie_Misc::element_implode($element); + $data = str_replace($element['full'], $new_element, $data); + $element['full'] = $new_element; + } + } + } + elseif (isset($element['attribs'][$attributes]['data'])) + { + $element['attribs'][$attributes]['data'] = SimplePie_Misc::absolutize_url($element['attribs'][$attributes]['data'], $this->base); + $data = str_replace($element['full'], SimplePie_Misc::element_implode($element), $data); + } + } + } + return $data; + } + + function do_strip_htmltags($match) + { + if ($this->encode_instead_of_strip) + { + if (isset($match[4]) && !in_array(strtolower($match[1]), array('script', 'style'))) + { + $match[1] = htmlspecialchars($match[1], ENT_COMPAT, 'UTF-8'); + $match[2] = htmlspecialchars($match[2], ENT_COMPAT, 'UTF-8'); + return "<$match[1]$match[2]>$match[3]</$match[1]>"; + } + else + { + return htmlspecialchars($match[0], ENT_COMPAT, 'UTF-8'); + } + } + elseif (isset($match[4]) && !in_array(strtolower($match[1]), array('script', 'style'))) + { + return $match[4]; + } + else + { + return ''; + } + } +} + +?> \ No newline at end of file diff --git a/oss/vtiger/trunk/vtlib/vtlib-Copyright.txt b/oss/vtiger/trunk/vtlib/vtlib-Copyright.txt new file mode 100644 index 00000000..71b8ec91 --- /dev/null +++ b/oss/vtiger/trunk/vtlib/vtlib-Copyright.txt @@ -0,0 +1,37 @@ +vtlib uses third party libraries to enable certain functionality. + +1. For creating and unpacking zip files +-- ==================================== +vtlib/thirdparty/dZip.php +vtlib/thirdparty/dUnzip2.inc.php + +DOWNLOAD URL: +http://www.phpclasses.org/browse/package/2495/ + +BSD License: http://www.opensource.org/licenses/bsd-license.html + +NOTE: Bug Fix was added to function addFile of dZip class. + +2. For Feed Parsing +-- =============== +vtlib/thirdparty/parser/feed/simplepie.inc + +DOWNLOAD URL: http://simplepie.org + +BSD License: http://www.opensource.org/licenses/bsd-license.php + +3. For HTTP Communication +-- ====================== +Vtiger_Net_Client is based on the following: + +http://pear.php.net/package/HTTP_Request +[License: http://www.opensource.org/licenses/bsd-license.php] + +http://pear.php.net/package/Net_URL +[License: http://www.opensource.org/licenses/bsd-license.php] + +http://pear.php.net/package/Net_Socket +[License: http://www.php.net/license/3_01.txt] + +http://pear.php.net/package/PEAR (Only PEAR.php) +[License: http://www.php.net/license/3_01.txt] \ No newline at end of file