adamjakab /
SuiteCRM
This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
| 1 | <?PHP |
||
| 2 | /********************************************************************************* |
||
| 3 | * SugarCRM Community Edition is a customer relationship management program developed by |
||
| 4 | * SugarCRM, Inc. Copyright (C) 2004-2013 SugarCRM Inc. |
||
| 5 | * |
||
| 6 | * This program is free software; you can redistribute it and/or modify it under |
||
| 7 | * the terms of the GNU Affero General Public License version 3 as published by the |
||
| 8 | * Free Software Foundation with the addition of the following permission added |
||
| 9 | * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK |
||
| 10 | * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY |
||
| 11 | * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. |
||
| 12 | * |
||
| 13 | * This program is distributed in the hope that it will be useful, but WITHOUT |
||
| 14 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
||
| 15 | * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more |
||
| 16 | * details. |
||
| 17 | * |
||
| 18 | * You should have received a copy of the GNU Affero General Public License along with |
||
| 19 | * this program; if not, see http://www.gnu.org/licenses or write to the Free |
||
| 20 | * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |
||
| 21 | * 02110-1301 USA. |
||
| 22 | * |
||
| 23 | * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, |
||
| 24 | * SW2-130, Cupertino, CA 95014, USA. or at email address [email protected]. |
||
| 25 | * |
||
| 26 | * The interactive user interfaces in modified source and object code versions |
||
| 27 | * of this program must display Appropriate Legal Notices, as required under |
||
| 28 | * Section 5 of the GNU Affero General Public License version 3. |
||
| 29 | * |
||
| 30 | * In accordance with Section 7(b) of the GNU Affero General Public License version 3, |
||
| 31 | * these Appropriate Legal Notices must retain the display of the "Powered by |
||
| 32 | * SugarCRM" logo. If the display of the logo is not reasonably feasible for |
||
| 33 | * technical reasons, the Appropriate Legal Notices must display the words |
||
| 34 | * "Powered by SugarCRM". |
||
| 35 | ********************************************************************************/ |
||
| 36 | |||
| 37 | /** |
||
| 38 | * THIS CLASS IS FOR DEVELOPERS TO MAKE CUSTOMIZATIONS IN |
||
| 39 | */ |
||
| 40 | 1 | require_once('modules/AOD_Index/AOD_Index_sugar.php'); |
|
| 41 | 1 | require_once('modules/AOD_Index/LuceneUtils.php'); |
|
| 42 | 1 | requireLucene(); |
|
| 43 | |||
| 44 | class AOD_Index extends AOD_Index_sugar { |
||
| 45 | |||
| 46 | 84 | function __construct(){ |
|
| 47 | 84 | parent::__construct(); |
|
| 48 | 84 | Zend_Search_Lucene_Search_QueryParser::setDefaultEncoding('utf-8'); |
|
| 49 | 84 | Zend_Search_Lucene_Analysis_Analyzer::setDefault(new Zend_Search_Lucene_Analysis_Analyzer_Common_Utf8Num_CaseInsensitive()); |
|
| 50 | 84 | } |
|
| 51 | |||
| 52 | /** |
||
| 53 | * @deprecated deprecated since version 7.6, PHP4 Style Constructors are deprecated and will be remove in 7.8, please update your code, use __construct instead |
||
| 54 | */ |
||
| 55 | function AOD_Index(){ |
||
| 56 | $deprecatedMessage = 'PHP4 Style Constructors are deprecated and will be remove in 7.8, please update your code'; |
||
| 57 | if(isset($GLOBALS['log'])) { |
||
| 58 | $GLOBALS['log']->deprecated($deprecatedMessage); |
||
| 59 | } |
||
| 60 | else { |
||
| 61 | trigger_error($deprecatedMessage, E_USER_DEPRECATED); |
||
| 62 | } |
||
| 63 | self::__construct(); |
||
| 64 | } |
||
| 65 | |||
| 66 | |||
| 67 | 71 | function isEnabled(){ |
|
| 68 | 71 | global $sugar_config; |
|
| 69 | 71 | return !empty($sugar_config['aod']['enable_aod']); |
|
| 70 | } |
||
| 71 | |||
| 72 | 1 | function find($queryString){ |
|
| 73 | 1 | $queryString = strtolower($queryString); |
|
| 74 | 1 | $hits = $this->getLuceneIndex()->find($queryString); |
|
| 75 | 1 | return $hits; |
|
| 76 | } |
||
| 77 | |||
| 78 | 1 | function optimise(){ |
|
| 79 | 1 | if(!$this->isEnabled()){ |
|
| 80 | return; |
||
| 81 | } |
||
| 82 | 1 | global $timedate; |
|
| 83 | 1 | $this->getLuceneIndex()->optimize(); |
|
| 84 | 1 | $this->last_optimised = $timedate->getNow()->asDb(); |
|
| 85 | 1 | $this->save(); |
|
| 86 | 1 | } |
|
| 87 | |||
| 88 | 71 | public function getIndex(){ |
|
| 89 | 71 | $index = BeanFactory::getBean('AOD_Index',1); |
|
| 90 | 71 | if(!empty($index) && !empty($index->id)){ |
|
| 91 | 70 | return $index; |
|
| 92 | }else{ |
||
| 93 | 1 | $index = new AOD_Index(); |
|
| 94 | 1 | $index->id = 1; |
|
| 95 | 1 | $index->new_with_id = true; |
|
| 96 | 1 | $index->name = "Index"; |
|
| 97 | 1 | $index->location = "modules/AOD_Index/Index/Index"; |
|
| 98 | 1 | $index->save(); |
|
| 99 | 1 | return $index; |
|
| 100 | } |
||
| 101 | } |
||
| 102 | |||
| 103 | /** |
||
| 104 | * @param $revision |
||
| 105 | * @return bool|Zend_Search_Lucene_Document |
||
| 106 | */ |
||
| 107 | 1 | private function getDocumentForRevision($revision){ |
|
| 108 | 1 | $path = getDocumentRevisionPath($revision->id); |
|
| 109 | 1 | if(!file_exists($path)){ |
|
| 110 | 1 | return array("error"=>"File not found"); |
|
| 111 | } |
||
| 112 | //Convert the file to a lucene document |
||
| 113 | $mime = $revision->file_mime_type; |
||
| 114 | switch($mime){ |
||
| 115 | case 'application/pdf': |
||
| 116 | $document = createPDFDocument($path); |
||
| 117 | break; |
||
| 118 | case 'application/msword': |
||
| 119 | $document = createDocDocument($path); |
||
| 120 | break; |
||
| 121 | case 'application/vnd.oasis.opendocument.text': |
||
| 122 | $document = createOdtDocument($path); |
||
| 123 | break; |
||
| 124 | case 'application/vnd.openxmlformats-officedocument.wordprocessingml.document': |
||
| 125 | $document = createDocXDocument($path); |
||
| 126 | break; |
||
| 127 | case 'text/html': |
||
| 128 | $document = createHTMLDocument($path); |
||
| 129 | break; |
||
| 130 | case 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': |
||
| 131 | $document = createXLSXDocument($path); |
||
| 132 | break; |
||
| 133 | case 'application/rtf': |
||
|
0 ignored issues
–
show
Coding Style
introduced
by
Loading history...
|
|||
| 134 | $document = createRTFDocument($path); |
||
| 135 | case 'text/csv': |
||
| 136 | case 'text/plain': |
||
| 137 | $document = createTextDocument($path); |
||
| 138 | break; |
||
| 139 | case 'application/vnd.openxmlformats-officedocument.presentationml.presentation': |
||
| 140 | $document = createPPTXDocument($path); |
||
| 141 | break; |
||
| 142 | case 'application/vnd.oasis.opendocument.spreadsheet': |
||
| 143 | case 'application/vnd.ms-powerpoint': |
||
| 144 | case 'application/vnd.ms-excel': |
||
| 145 | default: |
||
| 146 | return array("error"=>"Mime type $mime not supported"); |
||
| 147 | } |
||
| 148 | if(!$document){ |
||
| 149 | return array("error"=>"Failed to parse document"); |
||
| 150 | } |
||
| 151 | $document->addField(Zend_Search_Lucene_Field::text("filename",$revision->filename)); |
||
| 152 | return array("error"=>false,"document"=>$document); |
||
| 153 | } |
||
| 154 | |||
| 155 | 21 | public function getDocumentForBean(SugarBean $bean){ |
|
| 156 | 21 | if($bean->module_name == 'DocumentRevisions'){ |
|
| 157 | 1 | $document = $this->getDocumentForRevision($bean); |
|
| 158 | }else{ |
||
| 159 | 20 | $document = array("error"=>false,"document"=>new Zend_Search_Lucene_Document()); |
|
| 160 | } |
||
| 161 | 21 | if($document["error"]){ |
|
| 162 | 1 | return $document; |
|
| 163 | } |
||
| 164 | 20 | $document["document"]->addField(Zend_Search_Lucene_Field::Keyword("aod_id", $bean->module_name." ".$bean->id)); |
|
| 165 | 20 | $document["document"]->addField(Zend_Search_Lucene_Field::UnIndexed("record_id", $bean->id)); |
|
| 166 | 20 | $document["document"]->addField(Zend_Search_Lucene_Field::UnIndexed("record_module", $bean->module_name)); |
|
| 167 | 20 | foreach($GLOBALS['dictionary'][$bean->getObjectName()]['fields'] as $key => $field){ |
|
| 168 | 20 | switch($field['type']){ |
|
| 169 | 20 | case "enum": |
|
| 170 | 17 | if(property_exists($bean, $key)) { |
|
| 171 | 17 | $document["document"]->addField(Zend_Search_Lucene_Field::Keyword($key, strtolower($bean->$key),'UTF-8')); |
|
| 172 | } |
||
| 173 | 17 | break; |
|
| 174 | |||
| 175 | 20 | case "multienum": |
|
| 176 | if(property_exists($bean, $key)) { |
||
| 177 | $vals = unencodeMultienum($bean->$key); |
||
| 178 | $document["document"]->addField(Zend_Search_Lucene_Field::unStored($key, strtolower(implode(" ",$vals)),'UTF-8')); |
||
| 179 | } |
||
| 180 | break; |
||
| 181 | 20 | case "name": |
|
| 182 | 20 | case "phone": |
|
| 183 | 20 | case "html": |
|
| 184 | 20 | case "text": |
|
| 185 | 20 | case "url": |
|
| 186 | 20 | case "varchar": |
|
| 187 | 20 | if(property_exists($bean,$key)){ |
|
| 188 | 20 | $val = strtolower($bean->$key); |
|
| 189 | }else{ |
||
| 190 | 1 | $val = ''; |
|
| 191 | } |
||
| 192 | 20 | $field = Zend_Search_Lucene_Field::unStored($key, $val,'UTF-8'); |
|
| 193 | 20 | $field->boost = $this->getBoost($bean->module_name,$key); |
|
|
0 ignored issues
–
show
It seems like
$this->getBoost($bean->module_name, $key) can also be of type integer. However, the property $boost is declared as type double. Maybe add an additional type check?
Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly. For example, imagine you have a variable Either this assignment is in error or a type check should be added for that assignment. class Id
{
public $id;
public function __construct($id)
{
$this->id = $id;
}
}
class Account
{
/** @var Id $id */
public $id;
}
$account_id = false;
if (starsAreRight()) {
$account_id = new Id(42);
}
$account = new Account();
if ($account instanceof Id)
{
$account->id = $account_id;
}
Loading history...
|
|||
| 194 | 20 | $document["document"]->addField($field); |
|
| 195 | 20 | break; |
|
| 196 | 20 | case "address": |
|
| 197 | 20 | case "bool": |
|
| 198 | 20 | case "currency": |
|
| 199 | 20 | case "date": |
|
| 200 | 20 | case "datetimecombo": |
|
| 201 | 20 | case "decimal": |
|
| 202 | 20 | case "float": |
|
| 203 | 20 | case "iframe": |
|
| 204 | 20 | case "int": |
|
| 205 | 20 | case "radioenum": |
|
| 206 | 20 | case "relate": |
|
| 207 | default: |
||
| 208 | 20 | break; |
|
| 209 | } |
||
| 210 | } |
||
| 211 | |||
| 212 | 20 | return $document; |
|
| 213 | } |
||
| 214 | |||
| 215 | 20 | private function getBoost($module, $field){ |
|
| 216 | 20 | $fieldBoosts = array('name' =>0.5, 'first_name' => 0.5, 'last_name' => 0.5); |
|
| 217 | 20 | $moduleBoosts = array('Accounts' => 0.5, 'Contacts' => 0.5, 'Leads' => 0.5, 'Opportunities' => 0.5); |
|
| 218 | 20 | $boost = 1; |
|
| 219 | 20 | if(!empty($fieldBoosts[$field])){ |
|
| 220 | 20 | $boost += $fieldBoosts[$field]; |
|
| 221 | } |
||
| 222 | 20 | if(!empty($moduleBoosts[$module])){ |
|
| 223 | 1 | $boost += $moduleBoosts[$module]; |
|
| 224 | } |
||
| 225 | 20 | return $boost; |
|
| 226 | } |
||
| 227 | |||
| 228 | 20 | private function getIndexEvent($module, $beanId){ |
|
| 229 | 20 | global $timedate; |
|
| 230 | 20 | $indexEventBean = BeanFactory::getBean("AOD_IndexEvent"); |
|
| 231 | 20 | $indexEvents = $indexEventBean->get_full_list('',"aod_indexevent.record_id = '".$beanId."' AND aod_indexevent.record_module = '".$module."'"); |
|
| 232 | 20 | if($indexEvents){ |
|
| 233 | 3 | $indexEvent = $indexEvents[0]; |
|
| 234 | 3 | if(count($indexEvents) > 1){ |
|
| 235 | 3 | for($x = 1; $x < count($indexEvents); $x++){ |
|
|
0 ignored issues
–
show
It seems like you are calling the size function
count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.
If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration: for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}
// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
|
|||
| 236 | $duplicateIE = $indexEvents[$x]; |
||
| 237 | $duplicateIE->mark_deleted($duplicateIE->id); |
||
| 238 | } |
||
| 239 | } |
||
| 240 | |||
| 241 | }else{ |
||
| 242 | 20 | $indexEvent = BeanFactory::newBean("AOD_IndexEvent"); |
|
| 243 | 20 | $indexEvent->record_id = $beanId; |
|
| 244 | 20 | $indexEvent->record_module = $module; |
|
| 245 | } |
||
| 246 | /* |
||
| 247 | * "Now" is cached in the SugarBean which means for long running processes (such as the indexing scheduler) that |
||
| 248 | * the date_modified could be in the past. This caused issues when comparing the date modified of the event with that |
||
| 249 | * of a bean. Here we explicitly set the date modified to be the current date. |
||
| 250 | */ |
||
| 251 | 20 | $indexEvent->update_date_modified = false; |
|
| 252 | 20 | $indexEvent->date_modified = $timedate->asDb(new DateTime()); |
|
| 253 | 20 | return $indexEvent; |
|
| 254 | } |
||
| 255 | |||
| 256 | 1 | public function commit(){ |
|
| 257 | 1 | if(!$this->isEnabled()){ |
|
| 258 | return; |
||
| 259 | } |
||
| 260 | 1 | $this->getLuceneIndex()->commit(); |
|
| 261 | 1 | } |
|
| 262 | |||
| 263 | 70 | public static function isModuleSearchable($module,$beanName){ |
|
| 264 | 70 | $whiteList = array("DocumentRevisions","Cases"); |
|
| 265 | 70 | if(in_array($module,$whiteList)){ |
|
| 266 | 4 | return true; |
|
| 267 | } |
||
| 268 | 70 | $blackList = array("AOD_IndexEvent","AOD_Index","AOW_Actions","AOW_Conditions","AOW_Processed","SchedulersJobs"); |
|
| 269 | 70 | if(in_array($module,$blackList)){ |
|
| 270 | 33 | return false; |
|
| 271 | } |
||
| 272 | 58 | $manager = new VardefManager(); |
|
| 273 | 58 | $manager->loadVardef($module, $beanName); |
|
| 274 | 58 | if(empty($GLOBALS['dictionary'][$beanName]['unified_search'])){ |
|
| 275 | 43 | return false; |
|
| 276 | } |
||
| 277 | 23 | return true; |
|
| 278 | } |
||
| 279 | |||
| 280 | 68 | public function index($module, $beanId){ |
|
| 281 | try{ |
||
| 282 | 68 | if(!$this->isEnabled()){ |
|
| 283 | return; |
||
| 284 | } |
||
| 285 | 68 | if(empty($GLOBALS['beanList'][$module])){ |
|
| 286 | return false; |
||
| 287 | } |
||
| 288 | 68 | $bean_name = $GLOBALS['beanList'][$module]; |
|
| 289 | 68 | $bean = new $bean_name(); |
|
| 290 | 68 | if(!$bean || ! $bean instanceof SugarBean){ |
|
| 291 | return false; |
||
| 292 | } |
||
| 293 | |||
| 294 | 68 | if(!self::isModuleSearchable($module,BeanFactory::getObjectName($module))){ |
|
| 295 | 67 | return false; |
|
| 296 | } |
||
| 297 | |||
| 298 | 22 | $bean = $bean->retrieve($beanId); |
|
| 299 | 22 | if(!$bean){ |
|
| 300 | 2 | return false; |
|
| 301 | } |
||
| 302 | |||
| 303 | 20 | $indexEvent = $this->getIndexEvent($module,$beanId); |
|
| 304 | 20 | $indexEvent->name = $bean->get_summary_text(); |
|
| 305 | |||
| 306 | 20 | $document = $this->getDocumentForBean($bean); |
|
| 307 | //Index name, id, date, filename |
||
| 308 | 20 | if(!$document['error']){ |
|
| 309 | 19 | $this->remove($module,$beanId); |
|
| 310 | 19 | $this->getLuceneIndex()->addDocument($document['document']); |
|
| 311 | 19 | $indexEvent->success = true; |
|
| 312 | }else{ |
||
| 313 | 1 | $indexEvent->success = false; |
|
| 314 | 1 | $indexEvent->error = $document['error']; |
|
| 315 | } |
||
| 316 | 20 | $indexEvent->save(); |
|
| 317 | }catch(Exception $ex){ |
||
| 318 | $GLOBALS['log']->error($ex->getMessage()); |
||
| 319 | return false; |
||
| 320 | } |
||
| 321 | 20 | return true; |
|
| 322 | } |
||
| 323 | private function getIdForDoc($module, $beanId){ |
||
| 324 | return $module . " " . $beanId; |
||
| 325 | } |
||
| 326 | |||
| 327 | 45 | public function remove($module, $beanId){ |
|
| 328 | 45 | $term = new Zend_Search_Lucene_Index_Term($module.' '.$beanId, 'aod_id'); |
|
| 329 | 45 | $query = new Zend_Search_Lucene_Search_Query_Term($term); |
|
| 330 | 45 | $hits = $this->getLuceneIndex()->find($query); |
|
| 331 | 45 | foreach ($hits as $hit) { |
|
| 332 | 3 | $this->getLuceneIndex()->delete($hit->id); |
|
| 333 | } |
||
| 334 | 45 | } |
|
| 335 | |||
| 336 | /** |
||
| 337 | * Returns a handle on the actual lucene index. |
||
| 338 | * @return Zend_Search_Lucene_Interface |
||
| 339 | */ |
||
| 340 | 48 | private function getLuceneIndex(){ |
|
| 341 | 48 | if(file_exists($this->location)){ |
|
| 342 | 48 | $this->index = new Zend_Search_Lucene($this->location); |
|
| 343 | }else{ |
||
| 344 | 1 | $this->index = Zend_Search_Lucene::create($this->location); |
|
| 345 | } |
||
| 346 | 48 | $this->index->setMaxBufferedDocs(64); |
|
| 347 | //$this->index->setMaxMergeDocs(50); |
||
| 348 | 48 | Zend_Search_Lucene_Search_Query_Fuzzy::setDefaultPrefixLength(1); |
|
| 349 | 48 | $this->index->setMergeFactor(5); |
|
| 350 | 48 | return $this->index; |
|
| 351 | } |
||
| 352 | |||
| 353 | |||
| 354 | 1 | public function getIndexableModules(){ |
|
| 355 | 1 | $modules = array(); |
|
| 356 | 1 | $beanList = $GLOBALS['beanList']; |
|
| 357 | 1 | ksort($beanList); |
|
| 358 | 1 | foreach($beanList as $beanModule => $beanName){ |
|
| 359 | 1 | if(self::isModuleSearchable($beanModule,$beanName)){ |
|
| 360 | 1 | $modules[$beanModule] = $beanName; |
|
| 361 | } |
||
| 362 | } |
||
| 363 | 1 | return $modules; |
|
| 364 | } |
||
| 365 | } |
||
| 366 | ?> |
||
| 367 |