Issues (4069)

Security Analysis    not enabled

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

include/Sugarpdf/Sugarpdf.php (9 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2 1
if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
3
/*********************************************************************************
4
 * SugarCRM Community Edition is a customer relationship management program developed by
5
 * SugarCRM, Inc. Copyright (C) 2004-2013 SugarCRM Inc.
6
7
 * SuiteCRM is an extension to SugarCRM Community Edition developed by Salesagility Ltd.
8
 * Copyright (C) 2011 - 2014 Salesagility Ltd.
9
 *
10
 * This program is free software; you can redistribute it and/or modify it under
11
 * the terms of the GNU Affero General Public License version 3 as published by the
12
 * Free Software Foundation with the addition of the following permission added
13
 * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
14
 * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY
15
 * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
16
 *
17
 * This program is distributed in the hope that it will be useful, but WITHOUT
18
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
19
 * FOR A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more
20
 * details.
21
 *
22
 * You should have received a copy of the GNU Affero General Public License along with
23
 * this program; if not, see http://www.gnu.org/licenses or write to the Free
24
 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
25
 * 02110-1301 USA.
26
 *
27
 * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road,
28
 * SW2-130, Cupertino, CA 95014, USA. or at email address [email protected].
29
 *
30
 * The interactive user interfaces in modified source and object code versions
31
 * of this program must display Appropriate Legal Notices, as required under
32
 * Section 5 of the GNU Affero General Public License version 3.
33
 *
34
 * In accordance with Section 7(b) of the GNU Affero General Public License version 3,
35
 * these Appropriate Legal Notices must retain the display of the "Powered by
36
 * SugarCRM" logo and "Supercharged by SuiteCRM" logo. If the display of the logos is not
37
 * reasonably feasible for  technical reasons, the Appropriate Legal Notices must
38
 * display the words  "Powered by SugarCRM" and "Supercharged by SuiteCRM".
39
 ********************************************************************************/
40
41
42
43 1
if(file_exists('custom/include/Sugarpdf/sugarpdf_config.php')){
44
    require_once('custom/include/Sugarpdf/sugarpdf_config.php');
45
} else {
46 1
    require_once('include/Sugarpdf/sugarpdf_config.php');
47
}
48
49 1
require_once('include/tcpdf/tcpdf.php');
50 1
require_once('include/Sugarpdf/SugarpdfHelper.php');
51
52
class Sugarpdf extends TCPDF
53
{
54
    /**
55
     * Stretch options constants
56
     */
57
    const STRETCH_NONE = 0;
58
    const STRETCH_SCALE = 1;
59
    const STRETCH_SCALE_FORCED = 2;
60
    const STRETCH_SPACING = 3;
61
    const STRETCH_SPACING_FORCED = 4;
62
63
    /**
64
     * This array is meant to hold an objects/data that we would like to pass between
65
     * the controller and the view.  The bean will automatically be set for us, but this
66
     * is meant to hold anything else.
67
     */
68
    var $sugarpdf_object_map = array();
69
    /**
70
     * The name of the current module.
71
     */
72
    var $module = '';
73
    /**
74
     * The name of the current action.
75
     */
76
    var $action = '';
77
    /**
78
     */
79
    var $bean = null;
80
     /**
81
     * Any errors that occured this can either be set by the view or the controller or the model
82
     */
83
    var $errors = array();
84
    /**
85
     * Use to set the filename of the output pdf file.
86
     */
87
    var $fileName = PDF_FILENAME;
88
    /**
89
     * Use for the ACL access.
90
     */
91
    var $aclAction = PDF_ACL_ACCESS;
92
    /**
93
     * Constructor which will peform the setup.
94
     */
95
96
97
    function __construct($bean = null, $sugarpdf_object_map = array(),$orientation=PDF_PAGE_ORIENTATION, $unit=PDF_UNIT, $format=PDF_PAGE_FORMAT, $unicode=true, $encoding='UTF-8', $diskcache=false){
98
        global $locale;
99
      //  $encoding = $locale->getExportCharset();
100
        if(empty($encoding)){
101
            $encoding = "UTF-8";
102
        }
103
        parent::__construct($orientation,$unit,$format,$unicode,$encoding,$diskcache);
104
        $this->module = $GLOBALS['module'];
105
        $this->bean = $bean;
106
        $this->sugarpdf_object_map = $sugarpdf_object_map;
107
        if(!empty($_REQUEST["sugarpdf"])){
108
            $this->action = $_REQUEST["sugarpdf"];
109
        }
110
    }
111
112
    /**
113
     * This method will be called from the controller and is not meant to be overridden.
114
     */
115
    function process(){
116
        $this->preDisplay();
117
        $this->display();
118
119
    }
120
121
    /**
122
     * This method will display the errors on the page.
123
     */
124
    function displayErrors(){
125
        foreach($this->errors as $error) {
126
            echo '<span class="error">' . $error . '</span><br>';
127
        }
128
    }
129
130
    /**
131
     * [OVERRIDE] - This method is meant to overidden in a subclass. The purpose of this method is
132
     * to allow a view to do some preprocessing before the display method is called. This becomes
133
     * useful when you have a view defined at the application level and then within a module
134
     * have a sub-view that extends from this application level view.  The application level
135
     * view can do the setup in preDisplay() that is common to itself and any subviews
136
     * and then the subview can just override display(). If it so desires, can also override
137
     * preDisplay().
138
     */
139
    function preDisplay(){
140
        // set document information
141
        $this->SetCreator(PDF_CREATOR);
142
        $this->SetAuthor(PDF_AUTHOR);
143
        $this->SetTitle(PDF_TITLE);
144
        $this->SetSubject(PDF_SUBJECT);
145
        $this->SetKeywords(PDF_KEYWORDS);
146
147
        // set other properties
148
        $compression=false;
149
        if(PDF_COMPRESSION == "on"){
150
            $compression=true;
151
        }
152
        $this->SetCompression($compression);
153
        $protection=array();
154
        if(PDF_PROTECTION != ""){
155
            $protection=explode(",",PDF_PROTECTION);
156
        }
157
158
        $this->SetProtection($protection,blowfishDecode(blowfishGetKey('sugarpdf_pdf_user_password'), PDF_USER_PASSWORD),blowfishDecode(blowfishGetKey('sugarpdf_pdf_owner_password'), PDF_OWNER_PASSWORD));
159
        $this->setCellHeightRatio(K_CELL_HEIGHT_RATIO);
160
        $this->setJPEGQuality(intval(PDF_JPEG_QUALITY));
161
        $this->setPDFVersion(PDF_PDF_VERSION);
162
163
        // set default header data
164
        $this->setHeaderData(PDF_HEADER_LOGO, PDF_HEADER_LOGO_WIDTH, PDF_HEADER_TITLE, PDF_HEADER_STRING);
165
166
        // set header and footer fonts
167
        $this->setHeaderFont(Array(PDF_FONT_NAME_MAIN, '', PDF_FONT_SIZE_MAIN));
168
        $this->setFooterFont(Array(PDF_FONT_NAME_DATA, '', PDF_FONT_SIZE_DATA));
169
170
        //set margins
171
        $this->SetMargins(PDF_MARGIN_LEFT, PDF_MARGIN_TOP, PDF_MARGIN_RIGHT);
172
        $this->setHeaderMargin(PDF_MARGIN_HEADER);
173
        $this->setFooterMargin(PDF_MARGIN_FOOTER);
174
175
        //set auto page breaks
176
        $this->SetAutoPageBreak(TRUE, PDF_MARGIN_BOTTOM);
177
178
        //set image scale factor
179
        $this->setImageScale(PDF_IMAGE_SCALE_RATIO);
180
181
        //set some language-dependent strings
182
        //$this->setLanguageArray($l);
183
184
        // ---------------------------------------------------------
185
186
    }
187
188
    /**
189
     * [OVERRIDE] - This method is meant to overidden in a subclass.
190
     */
191
    function display(){
192
        $this->AddPage();
193
        $this->SetFont(PDF_FONT_NAME_MAIN,'B',16);
194
        $this->MultiCell(0,0,'Tcpdf class for this module and action has not been implemented.',0,'C');
195
        $this->Info();
196
197
198
    }
199
200
    /**
201
     * [OVERRIDE]
202
     * This method override the regular Header() method to enable the custom image directory in addition to the OOB image directory.
203
     * This method is used to render the page header.
204
     * It is automatically called by AddPage().
205
     * @access public
206
    * @see include/tcpdf/TCPDF#Header()
207
     */
208
    public function Header() {
209
        $ormargins = $this->getOriginalMargins();
210
        $headerfont = $this->getHeaderFont();
211
        $headerdata = $this->getHeaderData();
212
213
        if (($headerdata['logo']) AND ($headerdata['logo'] != K_BLANK_IMAGE)) {
214
215
            // START SUGARPDF
216
            $logo = K_PATH_CUSTOM_IMAGES.$headerdata['logo'];
217
            $imsize = @getimagesize($logo);
218
            if ($imsize === FALSE) {
219
                // encode spaces on filename
220
                $logo = str_replace(' ', '%20', $logo);
221
                $imsize = @getimagesize($logo);
222
                if ($imsize === FALSE) {
223
                    $logo = K_PATH_IMAGES.$headerdata['logo'];
224
                }
225
            }
226
            // END SUGARPDF
227
228
            $this->Image($logo, $this->GetX(), $this->getHeaderMargin(), $headerdata['logo_width']);
0 ignored issues
show
It seems like $this->GetX() targeting TCPDF::GetX() can also be of type integer; however, TCPDF::Image() does only seem to accept string|double, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
229
            $imgy = $this->getImageRBY();
230
        } else {
231
            $imgy = $this->GetY();
232
        }
233
        $cell_height = round(($this->getCellHeightRatio() * $headerfont[2]) / $this->getScaleFactor(), 2);
234
        // set starting margin for text data cell
235
        if ($this->getRTL()) {
236
            $header_x = $ormargins['right'] + ($headerdata['logo_width'] * 1.1);
237
        } else {
238
            $header_x = $ormargins['left'] + ($headerdata['logo_width'] * 1.1);
239
        }
240
        $this->SetTextColor(0, 0, 0);
241
        // header title
242
        $this->SetFont($headerfont[0], 'B', $headerfont[2] + 1);
243
        $this->SetX($header_x);
244
        $this->Cell(0, $cell_height, $headerdata['title'], 0, 1, '', 0, '', 0);
245
        // header string
246
        $this->SetFont($headerfont[0], $headerfont[1], $headerfont[2]);
247
        $this->SetX($header_x);
248
        $this->MultiCell(0, $cell_height, $headerdata['string'], 0, '', 0, 1, '', '', true, 0, false);
249
        // print an ending header line
250
        $this->SetLineStyle(array('width' => 0.85 / $this->getScaleFactor(), 'cap' => 'butt', 'join' => 'miter', 'dash' => 0, 'color' => array(0, 0, 0)));
251
        $this->SetY((2.835 / $this->getScaleFactor()) + max($imgy, $this->GetY()));
252
        if ($this->getRTL()) {
253
            $this->SetX($ormargins['right']);
254
        } else {
255
            $this->SetX($ormargins['left']);
256
        }
257
        $this->Cell(0, 0, '', 'T', 0, 'C');
258
    }
259
260
    /**
261
    * [OVERRIDE] SetFont method in TCPDF Library
262
    * This method override the regular SetFont() method to enable the custom font directory in addition to the OOB font directory.
263
    *
264
    * @param string $family Family font. It can be either a name defined by AddFont() or one of the standard Type1 families (case insensitive):<ul><li>times (Times-Roman)</li><li>timesb (Times-Bold)</li><li>timesi (Times-Italic)</li><li>timesbi (Times-BoldItalic)</li><li>helvetica (Helvetica)</li><li>helveticab (Helvetica-Bold)</li><li>helveticai (Helvetica-Oblique)</li><li>helveticabi (Helvetica-BoldOblique)</li><li>courier (Courier)</li><li>courierb (Courier-Bold)</li><li>courieri (Courier-Oblique)</li><li>courierbi (Courier-BoldOblique)</li><li>symbol (Symbol)</li><li>zapfdingbats (ZapfDingbats)</li></ul> It is also possible to pass an empty string. In that case, the current family is retained.
265
    * @param string $style Font style. Possible values are (case insensitive):<ul><li>empty string: regular</li><li>B: bold</li><li>I: italic</li><li>U: underline</li><li>D: line trough</li></ul> or any combination. The default value is regular. Bold and italic styles do not apply to Symbol and ZapfDingbats basic fonts or other fonts when not defined.
266
    * @param float $size Font size in points. The default value is the current size. If no size has been specified since the beginning of the document, the value taken is 12
267
    * @param string $fontfile The font definition file. By default, the name is built from the family and style, in lower case with no spaces.
268
    * @access public
269
    * @see include/tcpdf/TCPDF#SetFont()
270
    */
271
    public function SetFont($family, $style='', $size=0, $fontfile='') {
272
273
        if(empty($fontfile) && defined('K_PATH_CUSTOM_FONTS')){
274
            // This will force addFont to search the custom directory for font before the OOB directory
275
            $fontfile = K_PATH_CUSTOM_FONTS."phantomFile.phantom";
276
        }
277
        parent::SetFont($family, $style, $size, $fontfile);
278
    }
279
280
    function Info(){
281
282
        $this->SetFont(PDF_FONT_NAME_MAIN,'',12);
283
        $this->MultiCell(0,0,'---',0,'L');
284
        $this->MultiCell(0,0,'Class: '.get_class($this),0,'L');
285
        $this->MultiCell(0,0,'Extends: '.get_parent_class($this),0,'L');
286
        $this->MultiCell(0,0,'---',0,'L');
287
        $this->MultiCell(0,0,'Module: '.$this->module,0,'L');
288
        $this->MultiCell(0,0,'Tcpdf Action: '.$this->action,0,'L');
289
        $this->MultiCell(0,0,'Bean ID: '.$this->bean->getFieldValue('id'),0,'L');
290
        $this->SetFont(PDF_FONT_NAME_MAIN,'',12);
291
        $this->MultiCell(0,0,'---',0,'L');
292
293
    }
294
295
    /**
296
     * [OVERRIDE] Cell method in tcpdf library.
297
     * Handle charset conversion and HTML entity decode.
298
     * This method override the regular Cell() method to apply the prepare_string() function to
299
     * the string to print in the PDF.
300
     * The cell method is used by all the methods which print text (Write, MultiCell).
301
     * @see include/tcpdf/TCPDF#Cell()
302
     */
303
    public function Cell($w, $h=0, $txt='', $border=0, $ln=0, $align='', $fill=0, $link='', $stretch=0) {
304
        parent::Cell($w, $h, prepare_string($txt), $border, $ln, $align, $fill, $link, $stretch);
305
    }
306
307
    /**
308
     * This Ln1() method will always print a line break of one line height.
309
     * The regular Ln() method print a line break which has the height of the last printed cell.
310
     */
311
    public function Ln1() {
312
        parent::Ln($this->FontSize * $this->cell_height_ratio + 2 * $this->cMargin, false);
313
    }
314
315
316
    /**
317
     * This method allow printing a table using the MultiCell method with a formatted options array in parameter
318
     * Options :
319
     * header options override the regular options for the header's cells - $options['header']
320
     * cell options override the regular options for the specific cell - Array[line number (0 to x)][cell header]['options']
321
     * @param $item Array[line number (0 to x)][cell header] = Cell content OR
322
     *              Array[line number (0 to x)][cell header]['value'] = Cell content AND
323
     *              Array[line number (0 to x)][cell header]['options'] = Array[cell properties] = values
324
     * @param $options Array which can contain : width (array 'column name'=>'width value + % OR nothing'), isheader (bool), header (array), fill (string: HTML color), ishtml (bool) default: false, border (0: no border (defaul), 1: frame or all of the following characters: L ,T ,R ,B), align (L: left align, C: center, R: right align, J: justification), stretch (array 'column name'=>stretch type)
325
     * @see MultiCell()
326
     */
327
    public function writeCellTable($item, $options=NULL)
328
    {
329
        // Save initial font values
330
        $fontFamily = $this->getFontFamily();
331
        $fontSize = $this->getFontSizePt();
332
        $fontStyle = $this->getFontStyle();
333
        $this->SetTextColor(0, 0, 0);
334
335
        $options = $this->initOptionsForWriteCellTable($options, $item);
336
337
        // HEADER
338
        if(!isset($options['isheader']) || $options['isheader'] == true){
339
            $headerOptions = $options;
340
            if(!empty($options['header']) && is_array($options['header'])){
341
                $headerOptions = $this->initOptionsForWriteCellTable($options['header'], $item);
342
            }
343
            foreach($item[0] as $k => $v){
344
                $header[$k]=$k;
345
            }
346
            $h = $this->getLineHeightFromArray($header, $options["width"]);
347
            foreach ($header as $v)
348
                $this->MultiCell($options["width"][$v],$h,$v,$headerOptions['border'],$headerOptions['align'],$headerOptions['fillstate'],0,'','',true, $options['stretch'][$v], $headerOptions['ishtml']);
349
            $this->SetFillColorArray($this->convertHTMLColorToDec($options['fill']));
0 ignored issues
show
It seems like $this->convertHTMLColorToDec($options['fill']) targeting TCPDF::convertHTMLColorToDec() can also be of type false; however, TCPDF::SetFillColorArray() does only seem to accept array, did you maybe forget to handle an error condition?
Loading history...
350
            $this->Ln();
351
        }
352
353
        // MAIN
354
        // default font
355
        $this->SetFont($fontFamily,$fontStyle,$fontSize);
356
        $this->SetTextColor(0, 0, 0);
357
        $even=true;
358
        $firstrow = true;
359
        // LINES
360
        foreach($item as $k=>$line){
361
            $even=!$even;
362
            $h = $this->getLineHeightFromArray($line, $options["width"]);
363
            // in the case when cell height is greater than page height
364
            // need to adjust the current page number
365
            // so the following output will not overlap the previous output
366
            if ($this->getNumPages() != $this->getPage()) {
367
                if (!empty($this->currentY)) {
368
                    $this->y = $this->currentY;
369
                    $this->currentY = 0;
370
                }
371
                $this->setPage($this->getNumPages());
372
            }
373
            $firstcell = true;
374
            //CELLS
375
            foreach($line as $kk=>$cell){
376
                $cellOptions = $options;
377
                $value = $cell;
378
379
                if(is_array($cell)){
380
                    $value = $cell['value'];
381
                    if(!empty($cell['options']) && is_array($cell['options'])){
382
                        $cellOptions = $this->initOptionsForWriteCellTable($cell['options'], $item);
383
                    }
384
                }
385
386
				//Bug45077-replacing single quote entities
387
					$value=str_replace("&#039;","'",$value);
388
				//Bug45077-replacing double quote entities
389
					$value=str_replace("&quot;",'"',$value);
390
391
                if($even && !empty($options['evencolor'])){
392
                    $this->SetFillColorArray($this->convertHTMLColorToDec($options['evencolor']));
0 ignored issues
show
It seems like $this->convertHTMLColorT...($options['evencolor']) targeting TCPDF::convertHTMLColorToDec() can also be of type false; however, TCPDF::SetFillColorArray() does only seem to accept array, did you maybe forget to handle an error condition?
Loading history...
393
                    $cellOptions['fillstate']=1;
394
                }else if(!$even && !empty($options['oddcolor'])){
395
                    $this->SetFillColorArray($this->convertHTMLColorToDec($options['oddcolor']));
0 ignored issues
show
It seems like $this->convertHTMLColorT...c($options['oddcolor']) targeting TCPDF::convertHTMLColorToDec() can also be of type false; however, TCPDF::SetFillColorArray() does only seem to accept array, did you maybe forget to handle an error condition?
Loading history...
396
                    $cellOptions['fillstate']=1;
397
                }
398
399
                if ($firstrow) {
400
                    $this->MultiCell($options["width"][$kk],$h,$value,$cellOptions['border'],$cellOptions['align'],$cellOptions['fillstate'],0,'','',true, $options['stretch'][$kk], $cellOptions['ishtml'], true, 0, false);
401
                } else {
402
                    if ($firstcell) {
403
                        // add page only once (for the first cell)
404
                        $this->MultiCell($options["width"][$kk],$h,$value,$cellOptions['border'],$cellOptions['align'],$cellOptions['fillstate'],0,'','',true,0,$cellOptions['ishtml'], true, 0, true);
405
                        $firstcell = false;
406
                    } else {
407
                        $this->MultiCell($options["width"][$kk],$h,$value,$cellOptions['border'],$cellOptions['align'],$cellOptions['fillstate'],0,'','',true,0,$cellOptions['ishtml'], true, 0, false);
408
                    }
409
                }
410
411
                $this->SetFillColorArray($this->convertHTMLColorToDec($options['fill']));
0 ignored issues
show
It seems like $this->convertHTMLColorToDec($options['fill']) targeting TCPDF::convertHTMLColorToDec() can also be of type false; however, TCPDF::SetFillColorArray() does only seem to accept array, did you maybe forget to handle an error condition?
Loading history...
412
            }
413
            $this->Ln();
414
            $firstrow = false;
415
        }
416
        $this->SetFont($fontFamily,$fontStyle,$fontSize);
417
        $this->SetTextColor(0, 0, 0);
418
    }
419
420
    /**
421
     * This method allow printing a table using the writeHTML method with a formatted array in parameter
422
     * This method can also return the table as HTML code
423
     * @param $item Array[line number (0 to x)][cell header] = Cell content OR
424
     *              Array[line number (0 to x)][cell header]['value'] = Cell content AND
425
     *              Array[line number (0 to x)][cell header]['options'] = Array[cell properties] = values
426
     * @param $returnHtml (bool) Return the table as HTML code instead of printing the HTML table
427
     * @param $options Array which can contain : table (array of "HTML proprty"=>"value"),td (array of "HTML proprty"=>"value"), tr (array of "HTML proprty"=>"value"), isheader(bool), header (array of "HTML proprty"=>"value"), width (array 'column name'=>'width value + unit OR nothing')
428
     * @return the HTML code if $returnHtml set to true
429
     */
430
    public function writeHTMLTable($item, $returnHtml=false, $options=NULL){
431
        //TODO ISSUE - width in % for the td have to be multiply by the number of column.
432
        //     ex: for a width of 20% in a table of 6 columns the width will have to be 120% (20*6).
433
        $html="";
434
        $line="";
435
        if(!empty($options)){
436
            foreach($options as $k=>$v){
437
                $tmp[strtolower($k)]=$v;
438
            }
439
            $options=$tmp;
440
        }else{
441
            $options=array();
442
        }
443
        if(!isset($options["isheader"]) || $options["isheader"] == true){
444
            if(!empty($options["header"])){
445
                foreach($options["header"] as $k=>$v){
446
                    $tmp[strtolower($k)]=$v;
447
                }
448
                $options["header"]=$tmp;
449
            }else{
450
                $options["header"]=array("tr"=>array("bgcolor"=>"#DCDCDC"),"td"=>array());
451
            }
452
453
            foreach($item[0] as $k => $v){
454
                if(!empty($options["width"]))$options["header"]["td"]["width"]=$options["width"][$k];
455
                $line.=$this->wrap("td", $k, $options["header"]);
456
            }
457
            $html.=$this->wrap("tr", $line, $options["header"]);
458
        }
459
        $even = true;
460
        foreach ($item as $k=>$v){
461
            $even = !$even;
462
            $line="";
463
464
            if($even){
465
                if (isset($options['evencolor']))
466
                {
467
                    $options["tr"]["bgcolor"] = $options['evencolor'];
468
                }
469
            } else {
470
                if (isset($options['oddcolor']))
471
                {
472
                    $options["tr"]["bgcolor"] = $options['oddcolor'];
473
                }
474
            }
475
            foreach($v as $kk => $vv){
476
                if(!empty($options["width"]) && isset($options["width"][$kk]))$options["td"]["width"]=$options["width"][$kk];
477
                $line.=$this->wrap("td", $vv, $options);
478
            }
479
            $html.=$this->wrap("tr", $line, $options);
480
        }
481
        $html=$this->wrap("table", $html, $options);
482
        if($returnHtml){
483
            return $html;
484
        }else{
485
            $this->writeHTML($html);
486
        }
487
    }
488
489
    /**
490
     * return the HTML code of the value wrap with the tag $tag. This method handle options (general and specific)
491
     * @param $tag
492
     * @param $value
493
     * @param $options
494
     * @return the HTML wrapped code
495
     */
496
    private function wrap($tag, $value, $options){
497
        if(empty($options[$tag])){
498
            $options[$tag] = array();
499
        }
500
        if(is_array($value)){
501
            if(isset($value["options"])){
502
                // The options of a specific entity overwrite the general options
503
                $options[$tag] = $value["options"];
504
            }
505
            if(isset($value["value"])){
506
                $value = $value["value"];
507
            }else{
508
                $value = "";
509
            }
510
        }
511
        return wrapTag($tag, $value, $options[$tag]);
512
    }
513
514
    /**
515
     * Return the heigth of a line depending of the width, the font and the content
516
     * @param $line Array containing the data of all the cells of the line
517
     * @param $width Array containing the width of all the cells of the line
518
     * @return The heigth of the line
519
     */
520
    private function getLineHeightFromArray($line, $width){
521
        $h=0;
522
        foreach($line as $kk=>$cell){
523
            $cellValue = $cell;
524
            if(is_array($cellValue)){
525
                $tmp = $cellValue['value'];
526
                $cellValue = $tmp;
527
            }
528
            if($h<$this->getNumLines($cellValue, $width[$kk])){
529
                $h=$this->getNumLines($cellValue, $width[$kk]);
530
            }
531
        }
532
        return $h * $this->FontSize * $this->cell_height_ratio + 2 * $this->cMargin;
533
    }
534
535
    /**
536
     * Private method for writeCellTable which format and initialize the options array.
537
     * @param $options array
538
     * @param $item array
539
     * @return $options array
0 ignored issues
show
The doc-type $options could not be parsed: Unknown type name "$options" at position 0. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
540
     */
541
    private function initOptionsForWriteCellTable($options, $item){
542
       if(!empty($options)){
543
            foreach($options as $k=>$v){
544
                $tmp[strtolower($k)]=$v;
545
            }
546
            $options=$tmp;
547
        }else{
548
            $options=array();
549
        }
550
        // set to default if empty
551
        if(empty($options["width"]) || !is_array($options["width"])){
552
            $colNum = count($item[0]);
553
            $defaultWidth = $this->getRemainingWidth()/$colNum;
554
            foreach($item[0] as $k => $v){
555
                $options["width"][$k]=$defaultWidth;
556
            }
557
        }else{
558
            foreach($options["width"] as $k => $v){
559
                $options["width"][$k] = $this->getHTMLUnitToUnits($v, $this->getRemainingWidth());
560
            }
561
562
        }
563
564
        if(empty($options["border"])){
565
            $options["border"]=0;
566
        }
567
568
        if(empty($options["align"])){
569
            $options["align"]="L";
570
        }
571
572
        if(empty($options['ishtml'])){
573
            $options['ishtml'] = false;
574
        }
575
        if(empty($options['border'])){
576
            $options['border'] = 0;
577
        }
578
        foreach($item[0] as $k => $v)
579
            if (empty($options['stretch'][$k]))
580
                $options['stretch'][$k] = self::STRETCH_NONE;
581
582
        if(!empty($options['fill'])){
583
            $this->SetFillColorArray($this->convertHTMLColorToDec($options['fill']));
0 ignored issues
show
It seems like $this->convertHTMLColorToDec($options['fill']) targeting TCPDF::convertHTMLColorToDec() can also be of type false; however, TCPDF::SetFillColorArray() does only seem to accept array, did you maybe forget to handle an error condition?
Loading history...
584
            $options['fillstate']=1;
585
        }else{
586
            $options['fill']="#FFFFFF";//white
587
            $options['fillstate']=0;
588
        }
589
590
        if(!empty($options['fontfamily'])){
591
            $fontFamily = $options['fontfamily'];
592
        }else{
593
            $fontFamily = $this->getFontFamily();
594
        }
595
        if(!empty($options['fontsize'])){
596
            $fontSize = $options['fontsize'];
597
        }else{
598
            $fontSize = $this->getFontSizePt();
599
        }
600
        if(!empty($options['fontstyle'])){
601
            $fontStyle = $options['fontstyle'];
602
        }else{
603
            $fontStyle = $this->getFontStyle();
604
        }
605
        if(!empty($options['textcolor'])){
606
            $this->SetTextColorArray($this->convertHTMLColorToDec($options['textcolor']));
0 ignored issues
show
It seems like $this->convertHTMLColorT...($options['textcolor']) targeting TCPDF::convertHTMLColorToDec() can also be of type false; however, TCPDF::SetTextColorArray() does only seem to accept array, did you maybe forget to handle an error condition?
Loading history...
607
        }else{
608
            $this->SetTextColor(0, 0, 0);//black
609
        }
610
611
        $this->SetFont($fontFamily, $fontStyle, $fontSize);
612
613
        return $options;
614
    }
615
616
    /**
617
    * This is method is fix for a better handling of the count. This method now handle the line break
618
    * between words.
619
    * This method returns the estimated number of lines required to print the text.
620
    * @param string $txt text to print
621
    * @param float $w width of cell. If 0, they extend up to the right margin of the page.
622
    * @return int Return the estimated number of lines.
623
    * @access public
624
    * @since 4.5.011
625
    * @OVERRIDE
626
    */
627
    public function getNumLines($txt, $w=0) {
628
        $lines = 0;
629
        if (empty($w) OR ($w <= 0)) {
630
            if ($this->rtl) {
631
                $w = $this->x - $this->lMargin;
632
            } else {
633
                $w = $this->w - $this->rMargin - $this->x;
634
            }
635
        }
636
        // max column width
637
        $wmax = $w - (2 * $this->cMargin);
638
        // remove carriage returns
639
        $txt = str_replace("\r", '', $txt);
640
        // divide text in blocks
641
        $txtblocks = explode("\n", $txt);
642
        // for each block;
643
        foreach ($txtblocks as $block) {
644
            // estimate the number of lines
645
            if(empty($block)){
646
                $lines++;
647
            // If the block is in more than one line
648
            }else if(ceil($this->GetStringWidth($block) / $wmax)>1){
649
                //divide into words
650
                $words = explode(" ", $block);
651
                //TODO explode with space is not the best things to do...
652
                $wordBlock = "";
653
                $first=true;
654
                $lastNum = 0;
655
                $run = false;
656
657
                for($i=0; $i<count($words); $i++){
0 ignored issues
show
Performance Best Practice introduced by
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...
658
                    if($first){
659
                        $wordBlock = $words[$i];
660
                    }else{
661
                        $wordBlock .= " ".$words[$i];
662
                    }
663
                    if(ceil($this->GetStringWidth($wordBlock) / $wmax)>1){
664
                        if($first){
665
                            $lastNum = ceil($this->GetStringWidth($wordBlock) / $wmax);
666
                            $run = true;
667
                            $first = false;
668
                        }else{
669
                            if($run && $lastNum == ceil($this->GetStringWidth($wordBlock) / $wmax)){
670
                                // save the number of line if it is the last loop
671
                                if($i+1 == count($words)){
672
                                    $lines += ceil($this->GetStringWidth($wordBlock) / $wmax);
673
                                }
674
                                continue;
675
                            }else{
676
                                $first = true;
677
                                $lines += ceil($this->GetStringWidth( substr($wordBlock, 0, (strlen($wordBlock) - strlen(" ".$words[$i]))) ) / $wmax);
678
                                $i--;
679
                                $lastNum = 0;
680
                                $run = false;
681
                            }
682
                        }
683
684
                    }else{
685
                        $first = false;
686
                    }
687
                    // save the number of line if it is the last loop
688
                    if($i+1 == count($words)){
689
                        $lines += ceil($this->GetStringWidth($wordBlock) / $wmax);
690
                    }
691
                }
692
693
            }else{
694
                $lines++;
695
            }
696
        }
697
        return $lines;
698
    }
699
700
    /**
701
     * Disable zlib output compression if we are downloading the PDF.
702
     *
703
     * @see TCPDF::Output()
704
     */
705
    public function Output($name='doc.pdf', $dest='I')
706
    {
707
        if ( $dest == 'I' || $dest == 'D') {
708
            ini_set('zlib.output_compression', 'Off');
709
        }
710
711
        return parent::Output($name,$dest);
712
    }
713
}
714
715