| @@ -26,11 +26,11 @@ | ||
| 26 | 26 | * |
| 27 | 27 | * @since 2.0.0 |
| 28 | 28 | * |
| 29 | 29 | * @param string $html Data to be parsed. |
| 30 | - * @return array|WP_Error Array with table data and options (current table head and foot row) on success, WP_Error on error. | |
| 30 | + * @return array<string, mixed>|WP_Error Array with table data and options (current table head and foot row) on success, WP_Error on error. | |
| 31 | 31 | */ |
| 32 | - public static function parse( $html ) { | |
| 32 | + public static function parse( string $html ) /* : array|WP_Error */ { | |
| 33 | 33 | if ( false === stripos( $html, '<table' ) || false === stripos( $html, '</table>' ) ) { |
| 34 | 34 | return new WP_Error( 'table_import_html_no_table_found' ); |
| 35 | 35 | } |
| 36 | 36 | |
| @@ -40,9 +40,9 @@ | ||
| 40 | 40 | /* |
| 41 | 41 | * Don't expand external entities, see https://websec.io/2012/08/27/Preventing-XXE-in-PHP.html. |
| 42 | 42 | * Silence warnings as the function is deprecated in PHP 8, but can be necessary with LIBXML_NOENT being defined, see https://core.trac.wordpress.org/changeset/50714. |
| 43 | 43 | */ |
| 44 | - @libxml_disable_entity_loader( true ); // phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged | |
| 44 | + @libxml_disable_entity_loader( true ); // phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged,Generic.PHP.DeprecatedFunctions.Deprecated | |
| 45 | 45 | } |
| 46 | 46 | // No warnings/errors raised, but stored internally. |
| 47 | 47 | libxml_use_internal_errors( true ); |
| 48 | 48 | $dom = new DOMDocument( '1.0', 'UTF-8' ); |
| @@ -47,10 +47,10 @@ | ||
| 47 | 47 | libxml_use_internal_errors( true ); |
| 48 | 48 | $dom = new DOMDocument( '1.0', 'UTF-8' ); |
| 49 | 49 | // No strict checking for invalid HTML. |
| 50 | 50 | $dom->strictErrorChecking = false; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase |
| 51 | - $dom->loadHTML( $full_html ); | |
| 52 | - if ( false === $dom ) { | |
| 51 | + $result = $dom->loadHTML( $full_html ); | |
| 52 | + if ( ! $result ) { | |
| 53 | 53 | return new WP_Error( 'table_import_html_dom_load_html_failed' ); |
| 54 | 54 | } |
| 55 | 55 | $dom_tables = $dom->getElementsByTagName( 'table' ); |
| 56 | 56 | if ( 0 === count( $dom_tables ) ) { |
| @@ -56,10 +56,10 @@ | ||
| 56 | 56 | if ( 0 === count( $dom_tables ) ) { |
| 57 | 57 | return new WP_Error( 'table_import_html_dom_get_tables' ); |
| 58 | 58 | } |
| 59 | 59 | libxml_clear_errors(); // Clear errors so that we only catch those inside the table in the next line. |
| 60 | - $table = simplexml_import_dom( $dom_tables->item( 0 ) ); | |
| 61 | - if ( false === $table ) { | |
| 60 | + $table = simplexml_import_dom( $dom_tables->item( 0 ) ); // @phpstan-ignore argument.type | |
| 61 | + if ( is_null( $table ) ) { | |
| 62 | 62 | return new WP_Error( 'table_import_html_simplexml_import_dom_failed' ); |
| 63 | 63 | } |
| 64 | 64 | |
| 65 | 65 | $errors = libxml_get_errors(); |
| @@ -64,19 +64,19 @@ | ||
| 64 | 64 | |
| 65 | 65 | $errors = libxml_get_errors(); |
| 66 | 66 | libxml_clear_errors(); |
| 67 | 67 | if ( ! empty( $errors ) ) { |
| 68 | - $output = '<strong>' . __( 'The imported file contains errors:', 'tablepress' ) . '</strong><br /><br />'; | |
| 68 | + $output = '<strong>' . __( 'The imported file contains errors:', 'tablepress' ) . '</strong><br><br>'; | |
| 69 | 69 | foreach ( $errors as $error ) { |
| 70 | 70 | switch ( $error->level ) { |
| 71 | 71 | case LIBXML_ERR_WARNING: |
| 72 | - $output .= "Warning {$error->code}: {$error->message} in line {$error->line}, column {$error->column}<br />"; | |
| 72 | + $output .= "Warning {$error->code}: {$error->message} in line {$error->line}, column {$error->column}<br>"; | |
| 73 | 73 | break; |
| 74 | 74 | case LIBXML_ERR_ERROR: |
| 75 | - $output .= "Error {$error->code}: {$error->message} in line {$error->line}, column {$error->column}<br />"; | |
| 75 | + $output .= "Error {$error->code}: {$error->message} in line {$error->line}, column {$error->column}<br>"; | |
| 76 | 76 | break; |
| 77 | 77 | case LIBXML_ERR_FATAL: |
| 78 | - $output .= "Fatal Error {$error->code}: {$error->message} in line {$error->line}, column {$error->column}<br />"; | |
| 78 | + $output .= "Fatal Error {$error->code}: {$error->message} in line {$error->line}, column {$error->column}<br>"; | |
| 79 | 79 | break; |
| 80 | 80 | } |
| 81 | 81 | } |
| 82 | 82 | wp_die( $output, 'Import Error', array( 'response' => 200, 'back_link' => true ) ); |
| @@ -86,20 +86,22 @@ | ||
| 86 | 86 | 'data' => array(), |
| 87 | 87 | 'options' => array(), |
| 88 | 88 | ); |
| 89 | 89 | if ( isset( $table->thead ) ) { |
| 90 | - $html_table['data'] = array_merge( $html_table['data'], self::_import_html_rows( $table->thead[0]->tr ) ); | |
| 91 | - $html_table['options']['table_head'] = true; | |
| 90 | + $head_rows = self::_import_html_rows( $table->thead[0]->tr ); // @phpstan-ignore property.nonObject | |
| 91 | + $html_table['data'] = array_merge( $html_table['data'], $head_rows ); | |
| 92 | + $html_table['options']['table_head'] = count( $head_rows ); | |
| 92 | 93 | } |
| 93 | 94 | if ( isset( $table->tbody ) ) { |
| 94 | - $html_table['data'] = array_merge( $html_table['data'], self::_import_html_rows( $table->tbody[0]->tr ) ); | |
| 95 | + $html_table['data'] = array_merge( $html_table['data'], self::_import_html_rows( $table->tbody[0]->tr ) ); // @phpstan-ignore property.nonObject | |
| 95 | 96 | } |
| 96 | 97 | if ( isset( $table->tr ) ) { |
| 97 | 98 | $html_table['data'] = array_merge( $html_table['data'], self::_import_html_rows( $table->tr ) ); |
| 98 | 99 | } |
| 99 | 100 | if ( isset( $table->tfoot ) ) { |
| 100 | - $html_table['data'] = array_merge( $html_table['data'], self::_import_html_rows( $table->tfoot[0]->tr ) ); | |
| 101 | - $html_table['options']['table_foot'] = true; | |
| 101 | + $foot_rows = self::_import_html_rows( $table->tfoot[0]->tr ); // @phpstan-ignore property.nonObject | |
| 102 | + $html_table['data'] = array_merge( $html_table['data'], $foot_rows ); | |
| 103 | + $html_table['options']['table_foot'] = count( $foot_rows ); | |
| 102 | 104 | } |
| 103 | 105 | |
| 104 | 106 | return $html_table; |
| 105 | 107 | } |
| @@ -109,11 +111,11 @@ | ||
| 109 | 111 | * |
| 110 | 112 | * @since 2.0.0 |
| 111 | 113 | * |
| 112 | 114 | * @param SimpleXMLElement $element XMLElement. |
| 113 | - * @return array SimpleXMLElement exported to an array. | |
| 115 | + * @return array<int, array<int, string>> SimpleXMLElement exported to an array. | |
| 114 | 116 | */ |
| 115 | - protected static function _import_html_rows( $element ) { | |
| 117 | + protected static function _import_html_rows( SimpleXMLElement $element ): array { | |
| 116 | 118 | $rows = array(); // Container for the table data. |
| 117 | 119 | $rowspans = array(); // Container for information about rowspans in rows that follow the currently processed row. |
| 118 | 120 | |
| 119 | 121 | $row_idx = 0; |
| @@ -118,9 +120,9 @@ | ||
| 118 | 120 | |
| 119 | 121 | $row_idx = 0; |
| 120 | 122 | foreach ( $element as $row ) { |
| 121 | 123 | // If all cells in a row should be merged with the cells in the row above, add the trigger word to each of them (should be very rare). |
| 122 | - while ( isset( $rowspans[ $row_idx ] ) && count( $rowspans[ $row_idx ] ) === count( $rows[ $row_idx - 1 ] ) ) { | |
| 124 | + while ( isset( $rowspans[ $row_idx ] ) && count( $rowspans[ $row_idx ] ) === count( $rows[ $row_idx - 1 ] ) ) { // phpcs:ignore Squiz.PHP.DisallowSizeFunctionsInLoops.Found | |
| 123 | 125 | $rows[] = $rowspans[ $row_idx ]; |
| 124 | 126 | ++$row_idx; |
| 125 | 127 | } |
| 126 | 128 | |
| @@ -132,15 +134,15 @@ | ||
| 132 | 134 | $new_row[] = $rowspans[ $row_idx ][ $column_idx ]; |
| 133 | 135 | ++$column_idx; |
| 134 | 136 | } |
| 135 | 137 | |
| 136 | - $cell_xml = $cell->asXml(); | |
| 138 | + $cell_xml = $cell->asXML(); | |
| 137 | 139 | |
| 138 | 140 | // Get content between <td>...</td>, or <th>...</th>, possibly with HTML. |
| 139 | - if ( 1 === preg_match( '#<t[d|h].*?>(.*)</t[d|h]>#is', $cell_xml, $matches ) ) { | |
| 141 | + if ( false !== $cell_xml && 1 === preg_match( '#<t[d|h].*?>(.*)</t[d|h]>#is', $cell_xml, $matches ) ) { | |
| 140 | 142 | /* |
| 141 | 143 | * Decode HTML entities again, as there might be some left especially in attributes of HTML tags in the cells, |
| 142 | - * see https://secure.php.net/manual/en/simplexmlelement.asxml.php#107137. | |
| 144 | + * see https://www.php.net/manual/en/simplexmlelement.asxml.php#107137. | |
| 143 | 145 | */ |
| 144 | 146 | $new_row[] = html_entity_decode( $matches[1], ENT_NOQUOTES, 'UTF-8' ); |
| 145 | 147 | |
| 146 | 148 | // Search for colspan and rowspan attributes in the cell's HTML tag. |
| @@ -186,9 +188,9 @@ | ||
| 186 | 188 | ++$row_idx; |
| 187 | 189 | } |
| 188 | 190 | |
| 189 | 191 | // After the last data row: If all cells in a row should be merged with the cells in the row above, add the trigger word to each of them (should be very rare). |
| 190 | - while ( isset( $rowspans[ $row_idx ] ) && count( $rowspans[ $row_idx ] ) === count( $rows[ $row_idx - 1 ] ) ) { | |
| 192 | + while ( isset( $rowspans[ $row_idx ] ) && count( $rowspans[ $row_idx ] ) === count( $rows[ $row_idx - 1 ] ) ) { // phpcs:ignore Squiz.PHP.DisallowSizeFunctionsInLoops.Found | |
| 191 | 193 | $rows[] = $rowspans[ $row_idx ]; |
| 192 | 194 | ++$row_idx; |
| 193 | 195 | } |
| 194 | 196 | |