yiisoft / yii2

Yii 2: The Fast, Secure and Professional PHP Framework
http://www.yiiframework.com
BSD 3-Clause "New" or "Revised" License
14.23k stars 6.91k forks source link

PHP Deprecated htmlspecialchars(): Passing null to parameter #19122

Closed pamparam83 closed 2 years ago

pamparam83 commented 2 years ago

What steps will reproduce the problem?

add error_reporting(E_ALL) in file web/index.php

open page login

What do you get instead?

PHP Deprecated Warning 'yii\base\ErrorException' with message 'htmlspecialchars(): Passing null to parameter #1 ($string) of type string is deprecated'

in /home/pamparam/PhpstormProjects/fix/framework/helpers/BaseHtml.php:118

Stack trace:

0 [internal function]: yii\base\ErrorHandler->handleError()

1 /home/pamparam/PhpstormProjects/fix/framework/helpers/BaseHtml.php(118): htmlspecialchars()

2 /home/pamparam/PhpstormProjects/fix/framework/helpers/BaseHtml.php(1353): yii\helpers\BaseHtml::encode()

3 /home/pamparam/PhpstormProjects/fix/framework/widgets/ActiveField.php(321): yii\helpers\BaseHtml::error()

4 /home/pamparam/PhpstormProjects/fix/framework/widgets/ActiveField.php(215): yii\widgets\ActiveField->error()

5 /home/pamparam/PhpstormProjects/fix/extensions/bootstrap4/src/ActiveField.php(244): yii\widgets\ActiveField->render()

6 /home/pamparam/PhpstormProjects/fix/framework/widgets/ActiveField.php(178): yii\bootstrap4\ActiveField->render()

7 /home/pamparam/PhpstormProjects/fix/apps/basic/views/site/login.php(29): yii\widgets\ActiveField->__toString()

8 /home/pamparam/PhpstormProjects/fix/framework/base/View.php(347): require('...')

Additional info

adding ternary solves this problem

public static function encode($content, $doubleEncode = true)
    {
        return htmlspecialchars($content ?: '', ENT_QUOTES | ENT_SUBSTITUTE, Yii::$app ? Yii::$app->charset : 'UTF-8',
                                $doubleEncode);
    }
Q A
Yii version 2.0.43
PHP version 8.1

19041

samdark commented 2 years ago

Do you have time for a pull request?

AndreyPootMay commented 2 years ago

@samdark can you check please

rob006 commented 2 years ago

According to PhpDoc, this method do not accept null.

Jeff-Sheedy commented 1 year ago
$content ?: ''

The ternary there will falsely pass '' into htmlspecialchars if $content is a non-null that simply evaluates to false like '0'; I'd do: isset($content) ? $content : ''

or an: if (!isset($content)){return $content;} as an early bailout in the first line of the encode() function.

tahir-56ali commented 1 month ago

@samdark

It appears that the fix for this issue, which was merged in version 2.0.43, is still missing in the latest version 2.0.49.3 etc. Could someone please verify if this fix has been included in the latest release or if there was an issue with merging it?

I have yii 2.0.49.3 and it is still showing old code here: vendor\yiisoft\yii2\helpers\BaseHtml.php and hence getting below error with PHP 8.2 PHP Warning – yii\base\ErrorException Array to string conversion

public static function encode($content, $doubleEncode = true) { return htmlspecialchars((string)$content, ENT_QUOTES | ENT_SUBSTITUTE, Yii::$app ? Yii::$app->charset : 'UTF-8', $doubleEncode); }

@samdark Could you please merge the fix the latest versions and particularly 2.0.49.3?

Thanks in advance!

rob006 commented 1 month ago

@tahir-56ali How to reproduce it? Array to string conversion suggests that you passed a wrong value to encode().

tahir-56ali commented 1 month ago

This is the complete Stack trace:

Stack trace:   | #0 /usr/share/nginx/html/vendor/yiisoft/yii2/helpers/BaseHtml.php(120): yii\base\ErrorHandler->handleError(2, 'Array to string...', '/usr/share/ngin...', 120)   | #1 /usr/share/nginx/html/vendor/yiisoft/yii2/i18n/Formatter.php(512): yii\helpers\BaseHtml::encode(Array)   | #2 [internal function]: yii\i18n\Formatter->asNtext(Array)   | #3 /usr/share/nginx/html/vendor/yiisoft/yii2/i18n/Formatter.php(463): call_user_func_array(Array, Array)   | #4 /usr/share/nginx/html/vendor/yiisoft/yii2/widgets/DetailView.php(180): yii\i18n\Formatter->format(Array, 'ntext')   | #5 /usr/share/nginx/html/vendor/yiisoft/yii2/widgets/DetailView.php(159): yii\widgets\DetailView->renderAttribute(Array, 12)   | #6 /usr/share/nginx/html/vendor/yiisoft/yii2/base/Widget.php(146): yii\widgets\DetailView->run()   | #7 /usr/share/nginx/html/views/public-listing/view.php(28): yii\base\Widget::widget(Array)   | #8 /usr/share/nginx/html/vendor/yiisoft/yii2/base/View.php(347): require('/usr/share/ngin...')   | #9 /usr/share/nginx/html/vendor/yiisoft/yii2/base/View.php(257): yii\base\View->renderPhpFile('/usr/share/ngin...', Array)   | #10 /usr/share/nginx/html/vendor/yiisoft/yii2/base/View.php(156): yii\base\View->renderFile('/usr/share/ngin...', Array, Object(app\controllers\PublicListingController))   | #11 /usr/share/nginx/html/vendor/yiisoft/yii2/base/Controller.php(407): yii\base\View->render('view', Array, Object(app\controllers\PublicListingController))   | #12 /usr/share/nginx/html/controllers/PublicListingController.php(61): yii\base\Controller->render('view', Array)   | #13 [internal function]: app\controllers\PublicListingController->actionView('1508')   | #14 /usr/share/nginx/html/vendor/yiisoft/yii2/base/InlineAction.php(57): call_user_func_array(Array, Array)   | #15 /usr/share/nginx/html/vendor/yiisoft/yii2/base/Controller.php(178): yii\base\InlineAction->runWithParams(Array)   | #16 /usr/share/nginx/html/vendor/yiisoft/yii2/base/Module.php(552): yii\base\Controller->runAction('view', Array)   | #17 /usr/share/nginx/html/vendor/yiisoft/yii2/web/Application.php(103): yii\base\Module->runAction('public-listing/...', Array)   | #18 /usr/share/nginx/html/vendor/yiisoft/yii2/base/Application.php(384): yii\web\Application->handleRequest(Object(yii\web\Request))   | #19 /usr/share/nginx/html/web/index.php(14): yii\base\Application->run()   | #20 {main}

It seems problem starts from here: /usr/share/nginx/html/vendor/yiisoft/yii2/i18n/Formatter.php(463): call_user_func_array(Array, Array)

Even though when I print - it shows that string is being passed:

public static function encode($content, $doubleEncode = true) { echo "

"; var_dump($content); exit; // outputs: string(9) "sometitle"
return htmlspecialchars((string)$content, ENT_QUOTES | ENT_SUBSTITUTE, Yii::$app ? Yii::$app->charset : 'UTF-8', $doubleEncode);
}

if I copy the fixed code from this issue manually in vendor\yiisoft\yii2\helpers\BaseHtml.php it fixes the issue

public static function encode($content, $doubleEncode = true)
{
    return htmlspecialchars($content ?: '', ENT_QUOTES | ENT_SUBSTITUTE, Yii::$app ? Yii::$app->charset : 'UTF-8',
                            $doubleEncode);
}
rob006 commented 1 month ago

if I copy the fixed code from this issue manually in vendor\yiisoft\yii2\helpers\BaseHtml.php it fixes the issue

public static function encode($content, $doubleEncode = true)
{
    return htmlspecialchars($content ?: '', ENT_QUOTES | ENT_SUBSTITUTE, Yii::$app ? Yii::$app->charset : 'UTF-8',
                            $doubleEncode);
}

This fix is incorrect, since int converts 0 to empty string, and it was never implemented (explicit cast to string was used instead). In your case it fixes your issue by accident by also converting empty array to empty string, but you should not have array here in the first place. I suggest do double check your code, since stack trace confirms that you're trying to render attribute with array using ntext formatter.

  | /usr/share/nginx/html/vendor/yiisoft/yii2/i18n/Formatter.php(512): yii\helpers\BaseHtml::encode(Array)
  | [internal function]: yii\i18n\Formatter->asNtext(Array)
  | /usr/share/nginx/html/vendor/yiisoft/yii2/i18n/Formatter.php(463): call_user_func_array(Array, Array)
  | /usr/share/nginx/html/vendor/yiisoft/yii2/widgets/DetailView.php(180): yii\i18n\Formatter->format(Array, 'ntext')
tahir-56ali commented 1 month ago

Thank you for your help and support!

Actually, issue was with my data - it was a json encoded data like a:2:{i:0;s:7:"test111";i:1;s:6:"test22";}

and in DetailView widget, It was using ntext formatter - that was causing issue. I had to use some custom formatter to properly format the data instead of using ntext formatter.

<?= DetailView::widget([ 'model' => $model, 'attributes' => [ 'benefits:ntext', ] ]) ?>