Version 4.2.0_20200308: ====================== Abstract -------- Now cooperating with the Composer ecosystem: the built-in autoloader stdlib/autoloader.php now aware of any currently available autoloader; can parse source files of a Composer-based project. PHP language support: several fixes to the PHP parser; arguments contravariance implemented; "use const ..." and "usefunction ..." implemented. Several fixes and enhancements to the stdlib: abstract DB connector strings; enhanced support for web apps, panels and controls. PHPLint package --------------- + A specific composer.json file is now provided to support integration with the Composer ecosystem. The PHPLint program, the autoloader.php and errors.php packages are now aware of this environment as detailed below. PHPLint Program --------------- + FIX: the "instanceof" operator after static method invocation was not supported, so did not pass if( C::M() instanceof C )... + FIX: fail with infinite loop parsing static method of interface. + Implements arguments contravariance (PHP bug #69612, fixed in PHP >= 7.4). See: https://www.php.net/manual/en/language.oop5.variance.php and https://bugs.php.net/bug.php?id=69612 . + Add support for "use const ..." and "use function ..." statements. + Anonymous functions are now parsed, although it's unlikely them will ever be fully supported by PHPLint. Proper usage of OOP is the recommended alternative. + Late static binding now passes validation but with Warning because PHPLint cannot check its proper usage; not sure if such a validation is even possible at all. + Add the new "--composer-project DIR" where DIR is the directory of project using the Composer files layout and classes resolution mechanism. All the composer.json files are then parsed and classes resolved accordingly. Note that PHPLint and all its libraries still rely on the internal autoloader stdlib/autoload.php. Example of command line, assuming the current working directory is that of the Composer-based project: $ phpl --composer-project . src/App/Entity/MyClass.php + phplint.tcl: add support for the new "--composer-project DIR" option. PHPLint Standard Library ------------------------ + autoload.php: now enables the PSR-4 class autoloader for the classes under the stdlib/ directory only if no other autoloader is detected. If any PHP autoloading mechanism is already set, give-up. If a Composer autoloader is detected, its "autoloader.php" file is required instead. So it's safe to include this package within any source file to take advantage of any class autoloader available. + errors.php: checking for the current php.ini file actually set is now disabled to reduce the "wtf" factor for novices of PHPLint. To restore a safer behavior uncomment the line //phplint_check_php_ini(); and enjoy how much time it could save you in the future. + it\icosaedro\io\DeflateOutputStream: (FIX) did not properly encoded the empty string due to the PHP bug 71395 introduced with PHP 7. Re-implemented by using the new incremental deflate functions. + it\icosaedro\io\DeflateInputStream: faster re-implementation using the new incremental deflate functions. + it\icosaedro\sql: + New SQLDriverManager::getConnection($dsn) static method to create a DB connection based on a connection string. + All the drivers provide a getConnection($params) static method to open a connection based on an associative arrays of parameters. + All the drivers now provide the getLastInsertId() method to retrieve the generated ID from the last insert. + it\icosaedro\web\bt_\UserSession: + All the arguments of the constructor (but the user name) removed and made accessible as public static properties, so basic features of the class (like the application properties) are now accessible even if the session is not established yet. + HTTP session cookie: added properties HttpOnly (access to the cookie is protected against JS) and SameSite=Strict (extra protection against CSRF; first line of protection were the non-sequential unpredictable "i" numbers of the generated URL). + it\icosaedro\web\*: (FIX) several important fixes to controls and forms: FIX: dot "." in control name is not supported by PHP as it mangled on postback to the underline "_"; introduced slash "/" and percent "%" instead that are now allowed in control name. FIX: on articulated nested form with panels, controls names where not properly build causing name collisions; now the name is a path that matches the nesting level of the control, like in "Form/panel1/ctrl1". + it\icosaedro\web\CodiceFiscale: (NEW) Italian Codice Fiscale normalization, formatting and validation. JavaScript implementation also provided. + it\icosaedro\web\CreditCardNumber: (NEW) CC normalization, formatting and validation. JavaScript implementation also provided. + it\icosaedro\web\ISBN: (NEW) ISBN normalization, formatting and validation. JavaScript implementation also provided. + it\icosaedro\web\PartitaIVA: (NEW) Italian Partita IVA normalization, formatting and validation. JavaScript implementation also provided. + it\icosaedro\web\controls\LineCombo: now saves the full list of suggested values between requests. This change simplifies building masks and should be mostly transparent to the existing source code. + it\icosaedro\web\controls\Select: now saves the full state of the control between requests, not only the selected value. This change simplifies building masks and should be mostly transparent to the existing source code. + it\icosaedro\web\controls\SelectMultiple: now saves the full state of the control between requests, not only the selected values. This change simplifies building masks and should be mostly transparent to the existing source code. + it\icosaedro\web\StaticContent: (NEW) static file delivery of files outside the document root of the web server; handy tool to keep static resources (CSS, JS, images, etc.) of the web app along its source code outside the document root, so simplifying software updates and deployment. + it\icosaedro\www\chat: (NEW) under this namespace, support for the Chat Rooms. Modules ------- Updated: calendar, core, date, dom, file, filter, gd, json, math, mcrypt, mhash, networking, openssl, pcre, phpinfo, session, spl, streams, tokenizer. New: opcache. Version 4.0_20190206: ==================== Abstract -------- PHPLint support for PHP type-hints has been extended and fixed, now targeting PHP 7.4, including nullable types and typed properties. Validation of PHP 5.6 source code is still available as an option. Several important bugs have been fixed. The complete source code of the Icosaedro Web Application (IWA) is now part of the distribution, including the Web Commenting System (WCS) and the Issues Tracking System (ITS). PHPLint program and related tools --------------------------------- + Fix: explicit local variable type declaration for "self" and "parent" like in /*. self .*/ $x = ... and /*. parent .*/ $x = ... were not recognized. + Fix: anonymous classes did not extend "object" so these types were not assignable to "object". + Fix: the 'void' type is now forbidden as formal argument of function and method, as type of element in array and as type of property. + Fix: now detects non-static access to static property $obj->staticProperty (forbidden by PHP). + Fix: now detects non-static access to static method $obj->staticMethod() (forbidden by PHPLint, although allowed by PHP). + Fix: now detects duplicated 'use' statements referring to the same alias class, that would otherwise cause a fatal PHP fatal parse error: use a\C; use b\C; // ERROR: duplicated 'C' alias use c\Z as C; // ERROR: duplicated 'C' alias + Fix: formal arguments passed by reference AND with default value were assumed being definitely assigned by PHPLint; now they are not anymore. This is because at run-time PHP assigns the default value to the optional argument if and only if the caller did not passed any argument at all; but if the caller passes an unset variable, then the default value is not assigned and the formal argument remains unassigned. Then in: function f(/*. int .*/ & $a = 123){...} the actual argument passed to the function must be a variable already set. See also the reference manual about functions for more; in particular, check for the 'return' meta-code modifier when the argument is an "out" value only. + Fix: silencer operator after value type-cast gave fatal error, for example: (int) @ $_GET['x'] + Fix: constants names defined with the define() statement cannot be PHP nor PHPLint meta-code keywords anymore, so declarations like these define("TRUE", 123); // PHP keyword define("Function", 123); // PHP keyword define("MIXED", 123); // PHPLint meta-code keyword are now detected as errors. + Fix: the += -= *= operators returned invalid int type when the left-hand side was float and the right-hand side was int (for example, $f += 1 gave int even if $f was determined being float). + Fix issue #35: evaluation of int/int was always assumed being float, but this is not always the case. For example, 6/2 gives int(3) at runtime, not float, so defeating type safety. As a general rule, now int/int always returns mixed because this expression could be evaluated either int or float depending from the specific run-time values of the operator. For the same reason $x /= $y is allowed only if $x is float; in fact, if $x were int, then the result could be either int or float depending on the current values of $x and $y. As a special case, if both the values are known (either because they are simply literal values or because of the static evaluation of a more complex expression involving only literals and named constants) then the actual quotient is evaluated and its type (either int or float) is guessed from the result. BEWARE. This change could have an heavy impact on existing code when the ratio ======= among two int numbers has to be calculated. In this case only, if the result has to be int, use intdiv($i,$j) (PHP7 only) or (int) ($i/$j) (PHP5, PHP7) If instead the result has to be float, apply a cast to float like in: (float) ($i/$j) No trouble instead if either the numerator or the denominator is already float: in this case the result is float for both PHPLint and PHP: 1/$f --> float if $f is float $i/2.0 --> float because 2.0 is float + Fix (issue #36): previously PHPLint allowed to assign int to variable of type float, and allowed to pass int as argument of function expecting float, so assuming an automatic int-to-float promotion. But this does not really happen at runtime, possibly defeating type safety. Now int values are not assignment compatible with float anymore, and an explicit type-cast must be applied where necessary. BEWARE. This change could have an heavy impact on existing code. The general ======= suggestion is to apply this conversion scheme (we assume $i be int and $f be float): +-------------------------+--------------------------+ | Before | Now | +-------------------------+--------------------------+ | $f = 2; | $f = 2.0; | | $f = $i; | $f = (float) $i; | | ... sqrt(2) ... | ... sqrt(2.0) ... | | ... abs($i) ... | ... abs((float) $i) ... | +-------------------------+--------------------------+ + Added PHP reserved keywords: iterable (unimplemented by PHPLint), mixed (unimplemented by PHP), numeric (unimplemented by PHP), resource (unimplemented by PHP). + New PHP 7 new type-hints and nullable types are now supported in formal argument of function and method, as return type of function and method, and as type of property (PHP 7.4) with some restrictions to comply with the PHPLint types model, where only some types (namely string, array, resource, mixed and objects) are nullable. Example showing mixed redundant annotations and PHP 7.4 type-hints: class MyClass { /** @var int */ public int $i = 0; // default value is mandatory for PHPLint (PHP?) /** @var ? string */ public ? string $s; /** * @param int $i * @param ? self $o * @return self */ function m(int $i, ? self $o): self { ... } } In more detail, type by type: About PHP 7 non-nullable types: void, bool, int, float: Supported. string, array, object, MyClass, self, parent: Supported. PHPLint still allows NULL to be assigned, which could result in a run-time fatal error if the "strict mode" is enabled. callable: NOT SUPPORTED. Suggested replacement: 'mixed' type as meta-code or DocBlock. About PHP 7 nullable types: ?bool, ?int, ?float: NOT SUPPORTED. Simple types cannot take NULL as value under PHPLint. Suggested replacement: 'mixed' type as meta-code or DocBlock or one of the container classes available under the it\icosaedro\containers namespace: BooleanClass, IntClass and FloatClass. ?string, ?array, ?object, ?MyClass, ?self, ?parent: Supported. ?callable: NOT SUPPORTED. Suggested replacement: 'mixed' type as meta-code or DocBlock. The nullable modifier '?' is allowed in DocBlock @param and @return line-tags only for string, array, resource, object (including self, parent, MyClass) but it is not reported in the generated documentation. PHPLint specific meta-code does not support the nullable '?' modifier, but meta-code annotations should not be used in normal code anyway. BEWARE. Typed properties is a new feature of PHP 7.4 still under development; the exact behavior at run-time of non-nullable properties is still under debate. In particular, un-initialized properties will take a new special default value "uninitialized" which is likely to generate unexpected runtime fatal errors. Reference: https://wiki.php.net/rfc/typed_properties_v2 BEWARE. The whole type-hint feature of PHP is still incomplete; several common types are missing: resource, mixed, parent, the structured array syntax E[K] introduced by PHPLint, and the generic classes. Workaround: resource, mixed, parent: use annotations (DocBlock or PHPLint meta-code). - Array: either annotation or mixed PHP code and meta-code, for example: function f( array/*.[int]string.*/ $names ){...} Note that "string[int]" and "array[int]string" are equivalent annotations for the same type for PHPLint, the first shorter and latter longer, but the latter is convenient to mix the part "array" that PHP will see, and the commented out part "/*.[int]string.*/" that PHP will ignore. - Generic classes: either annotation or mixed PHP code and meta-code, for example: function f( GenericHashMap/*..*/ $files ){...} + Fix: type-hinted and annotated methods signatures where assumed to be equivalent, but them are not from the PHP interpreter point of view, possibly resulting in a fatal run-time error. For example (using PHPLint meta-code annotations for brevity, but DocBlocks annotations do the same): class A { function m(/*. string .*/ $x): int {...} } class B extends A { /*. int .*/ function m(string $x){...} } passed validation but failed at run-time because from the PHP point of view B::m() "narrows" its argument type from "mixed" to "string" and changes its return type from int to mixed. Now PHPLint takes into account the difference between annotated and type-hinted signatures while evaluating method compatibility; the nullable modifier "?" is accounted as well. To make this important difference evident in the generated error messages and in the generated report, type-hints are reported within asterisks: void m(int $i); // annotated types in signature *void* m(*int* $i) // type-hinted types in signature Redundant annotations and type-hints can also be mixed together. For example, annotations can be the only way to cover the gaps in the current PHP type system, or DocBlocks can be required to add documentation. Types that are both annotated and type-hinted are then assumed type-hinted. + The PHPLint program, the phpl[.bat] script and the phplint.tcl script now all assume PHP 7 as default; use the --php-version 5 option for PHP 5. + Fixed and updated modules: core, date, dom, gmp, json, mysqli, spl, standard_reflection, zip. PHPLint Standard Library ------------------------ + Terser error reporting: on uncaught exception, now the error message reports the originating file and line number just in the very first line (previously the stdlib/error.php file and line number where indicated instead, forcing to look at the following stack trace to get the exact location of the error). + Fixed it\icosaedro\containers\BooleanClass: the getInstance() is now "static" as it should be in order to retrieve singleton instances of the "true" and "false" objects; the equals() method now recognizes and properly compares un-serialized objects. + it\icosaedro\web\bt_\UserSession: added the $secure flag to the constructor; if set, session cookie is sent only over HTTPS channel, and rejected then deleted if received over non-secure channel. + it\icosaedro\web\bt_\Form: added the browserBackEvent() and the browserReloadEvent() methods to capture navigation bar events from a bt_ form. + it\icosaedro\web\controls\Panel: added method addAttributes(). + it\icosaedro\web\controls\Select: method setValue() now throws the Unexpected- ValueException exception if the set value does not exist in the list. + it\icosaedro\web\controls\SelectMultiple: method setSelectedValue() now throws UnexpectedValueException if the set value does not exist in the list; method setSelectedValues() now throws UnexpectedValueException rather than RuntimeException if some value is not in the list. + New it\icosaedro\web\controls\LineCombo class implementing the HTML5 input data list control, basically a free line text entry box with associated list of already available values the user may choose from. + Under the it\icosaedro\www namespace, the complete www.icosaedro.it web application (IWA) including: - The Web Commenting System (WCS) that allows users to comment web pages (completely reworked). - Users registration and permissions management (completely reworked). - The Issue Tracking Systems (ITS), supporting multiple projects, attachment files, differentiated members permissions, issues search, email notifications. Version 3.2_20180727: ==================== ...