From 46c327e13a1c27201f1568f3c8da39160ea32719 Mon Sep 17 00:00:00 2001
From: Chris Sangwin <C.J.Sangwin@ed.ac.uk>
Date: Mon, 20 Jan 2025 22:27:44 +0000
Subject: [PATCH] Code style change.

---
 api/public/cors.php                                  |  8 ++++----
 classes/library_render.php                           |  4 ++--
 cli/ast_filter_tester.php                            |  2 +-
 cli/maximalibcheck.php                               | 10 +++++-----
 corsscripts/cors.php                                 |  6 +++---
 doc/docslib.php                                      |  2 +-
 doc/maintenance.php                                  |  4 ++--
 questiontype.php                                     |  2 +-
 stack/cas/cassession2.class.php                      |  2 +-
 stack/cas/castext2/blocks/iframe.block.php           |  2 +-
 stack/cas/castext2/castext2_evaluatable.class.php    |  2 +-
 stack/cas/connector.class.php                        |  8 ++++----
 stack/cas/connectorhelper.class.php                  |  2 +-
 stack/cas/keyval.class.php                           |  2 +-
 .../parsingrules/201_sig_figs_validation.filter.php  |  2 +-
 .../202_decimal_places_validation.filter.php         |  2 +-
 stack/cas/parsingrules/450_split_floats.filter.php   |  8 ++++----
 .../parsingrules/801_singleton_numeric.filter.php    |  6 +++---
 .../cas/parsingrules/802_singleton_units.filter.php  |  2 +-
 .../910_inert_float_for_display.filter.php           |  2 +-
 stack/input/dropdown/dropdown.class.php              |  2 +-
 stack/maximaparser/corrective_parser.php             | 12 ++++++------
 stack/prt.evaluatable.class.php                      |  2 +-
 stack/questionreport.class.php                       |  6 +++---
 stack/utils.class.php                                |  6 +++---
 tests/cassession2_test.php                           |  2 +-
 tests/fixtures/test_base.php                         |  4 ++--
 vle_specific.php                                     |  2 +-
 28 files changed, 57 insertions(+), 57 deletions(-)

diff --git a/api/public/cors.php b/api/public/cors.php
index 47a991cac..35fc6faad 100644
--- a/api/public/cors.php
+++ b/api/public/cors.php
@@ -27,10 +27,10 @@ if (isset($_GET['question'])) {
     $is_question = false;
 }
 
-if (strpos('..', $scriptname) !== false
-    || strpos('/', $scriptname) !== false
-    || strpos('\\', $scriptname) !== false) {
-    die("No such script here.");
+if (str_contains($scriptname, '..')
+    || str_contains($scriptname, '/')
+    || str_contains($scriptname, '\\')) {
+        die("No such script here.");
 }
 
 if (file_exists('../../corsscripts/' . $scriptname) || $scriptname === 'styles.css'
diff --git a/classes/library_render.php b/classes/library_render.php
index 5a9f15e9c..9c39b56b9 100644
--- a/classes/library_render.php
+++ b/classes/library_render.php
@@ -135,8 +135,8 @@ class library_render extends \external_api {
                 $cache->set($filepath, $result);
             } catch (\stack_exception $e) {
                 // If the question is not a STACK question we can't render it
-                // but we staill want users to be able to import it.
-                if (strpos($e->getMessage(), 'not of type STACK') !== false) {
+                // but we still want users to be able to import it.
+                if (str_contains($e->getMessage(), 'not of type STACK')) {
                     $xmldata = new SimpleXMLElement($qcontents);
                     $questiontext = (string) $xmldata->question->questiontext->text;
                     $questionname = (string) $xmldata->question->name->text;
diff --git a/cli/ast_filter_tester.php b/cli/ast_filter_tester.php
index 69eb9425e..de1234fca 100644
--- a/cli/ast_filter_tester.php
+++ b/cli/ast_filter_tester.php
@@ -133,7 +133,7 @@ $filters = stack_parsing_rule_factory::list_filters();
 if ($only !== false) {
     $f = [];
     foreach ($filters as $filter) {
-        if (strpos($filter, $only) !== false) {
+        if (str_contains($filter, $only)) {
             $f[] = $filter;
         }
     }
diff --git a/cli/maximalibcheck.php b/cli/maximalibcheck.php
index 11abc8616..ce8b1ddac 100644
--- a/cli/maximalibcheck.php
+++ b/cli/maximalibcheck.php
@@ -35,10 +35,10 @@ $globalvariablesused = [];
 
 // Get the files ../stack/maxima/*.mac.
 foreach (glob("../stack/maxima/*.mac") as $filename) {
-    if (strpos($filename, 'rtest_') !== false) {
+    if (str_contains($filename, 'rtest_')) {
         continue;
     }
-    if (strpos($filename, 'unittests_load.mac') !== false) {
+    if (str_contains($filename, 'unittests_load.mac')) {
         continue;
     }
 
@@ -62,7 +62,7 @@ foreach (glob("../stack/maxima/*.mac") as $filename) {
         }
     }
 
-    if (strpos($filename, 'assessment.mac') !== false) {
+    if (str_contains($filename, 'assessment.mac')) {
         // Some parser breaking cases. List calling and the wacky syntax of defines.
         $contents = str_replace('?\*autoconf\-version\*', '"cencored"', $contents);
         $contents = str_replace('define(UNARY_RECIP a, a^(-1)),', '"cencored",', $contents);
@@ -76,12 +76,12 @@ foreach (glob("../stack/maxima/*.mac") as $filename) {
         $contents = str_replace('ret:ev(exc1 %or exc2, simp)', 'ret:ev(exc1 or exc2, simp)', $contents);
     }
 
-    if (strpos($filename, 'stackmaxima.mac') !== false) {
+    if (str_contains($filename, 'stackmaxima.mac')) {
         // Some parser breaking cases.
         $contents = str_replace('?\*autoconf\-version\*', '"cencored"', $contents);
     }
 
-    if (strpos($filename, 'intervals.mac') !== false) {
+    if (str_contains($filename, 'intervals.mac')) {
         // Some parser breaking cases.
         $contents = str_replace('stack_single_variable_solver_rec(ex %and (v>=0), v)',
                 'stack_single_variable_solver_rec(ex and (v>=0), v)', $contents);
diff --git a/corsscripts/cors.php b/corsscripts/cors.php
index 6ff0481b7..ed11d73cd 100644
--- a/corsscripts/cors.php
+++ b/corsscripts/cors.php
@@ -22,9 +22,9 @@
 
 $scriptname = urldecode($_GET['name']);
 
-if (strpos('..', $scriptname) !== false
-    || strpos('/', $scriptname) !== false
-    || strpos('\\', $scriptname) !== false) {
+if (str_contains($scriptname, '..')
+    || str_contains($scriptname, '/')
+    || str_contains($scriptname, '\\')) {
     die("No such script here.");
 }
 
diff --git a/doc/docslib.php b/doc/docslib.php
index bc002b3a4..676964f13 100644
--- a/doc/docslib.php
+++ b/doc/docslib.php
@@ -136,7 +136,7 @@ function stack_docs_no_found($links) {
 function stack_docs_page($links, $file) {
     $preprocess = true;
     // This auto-generated file does not need maths processing.
-    if (strpos($file, 'Answer_Tests/Results') !== false) {
+    if (str_contains($file, 'Answer_Tests/Results')) {
         $preprocess = false;
     }
     $body = '';
diff --git a/doc/maintenance.php b/doc/maintenance.php
index 8e8065da6..e5c72f639 100644
--- a/doc/maintenance.php
+++ b/doc/maintenance.php
@@ -120,12 +120,12 @@ function report($d) {
                                         $link = implode('/', $segs);
 
                                         // Finally it looks like #--- are getting parsed in the request, let's omit them.
-                                        if (strpos($link, '#') !== false) {
+                                        if (str_contains($link, '#')) {
                                             $link = substr($link, 0, strpos($link, '#'));
                                         }
                                     }
                                     $hs = get_headers($link);
-                                    if (strpos($hs[0], '404') !== false) {
+                                    if (str_contains($hs[0], '404')) {
                                         $a[] = [$fpath, 'E', 'Error 404 [' . $found[1][$i] . '] appears to be a dead link.'];
                                     } else {
                                         $fileslinkedto[$found[0][$i]] = true;
diff --git a/questiontype.php b/questiontype.php
index c309f9a00..c1456e2d7 100644
--- a/questiontype.php
+++ b/questiontype.php
@@ -1926,7 +1926,7 @@ class qtype_stack extends question_type {
      * @return array updated $errors array.
      */
     protected function validate_cas_text($errors, $value, $fieldname, $fixingdollars, $session = null) {
-        if (!$fixingdollars && strpos($value, '$$') !== false) {
+        if (!$fixingdollars && str_contains($value, '$$')) {
             $errors[$fieldname][] = stack_string('forbiddendoubledollars');
         }
 
diff --git a/stack/cas/cassession2.class.php b/stack/cas/cassession2.class.php
index 5805b8968..2b4ef77c1 100644
--- a/stack/cas/cassession2.class.php
+++ b/stack/cas/cassession2.class.php
@@ -454,7 +454,7 @@ class stack_cas_session2 {
             $last = null;
             $errb = [];
             foreach ($err as $error) {
-                if (strpos($error->get_legacy_error(), 'STACK: ignore previous error.') !== false) {
+                if (str_contains($error->get_legacy_error(), 'STACK: ignore previous error.')) {
                     $last = null;
                 } else {
                     if ($last !== null) {
diff --git a/stack/cas/castext2/blocks/iframe.block.php b/stack/cas/castext2/blocks/iframe.block.php
index d9b206f45..fe9e929ba 100644
--- a/stack/cas/castext2/blocks/iframe.block.php
+++ b/stack/cas/castext2/blocks/iframe.block.php
@@ -151,7 +151,7 @@ class stack_cas_castext2_iframe extends stack_cas_castext2_block {
             $title = $parameters['title'];
             // Counter updates.
             foreach (self::$counters as $key => $value) {
-                if (strpos($title, $key) !== false) {
+                if (str_contains($title, $key)) {
                     $title = str_replace($key, '' . $value, $title);
                     self::$counters[$key] = $value + 1;
                 }
diff --git a/stack/cas/castext2/castext2_evaluatable.class.php b/stack/cas/castext2/castext2_evaluatable.class.php
index 14ebc52b0..4a76a624c 100644
--- a/stack/cas/castext2/castext2_evaluatable.class.php
+++ b/stack/cas/castext2/castext2_evaluatable.class.php
@@ -173,7 +173,7 @@ class castext2_evaluatable implements cas_raw_value_extractor {
         }
 
         if ($this->valid) {
-            if ($this->context === '/qt' || strpos($this->context, 'scenetext') !== false ||
+            if ($this->context === '/qt' || str_contains($this->context, 'scenetext') ||
                     $this->context === 'validation-questiontext') {
                 $options['in main content'] = true;
             }
diff --git a/stack/cas/connector.class.php b/stack/cas/connector.class.php
index 0ddc28450..f12a89197 100644
--- a/stack/cas/connector.class.php
+++ b/stack/cas/connector.class.php
@@ -190,7 +190,7 @@ abstract class stack_cas_connection_base implements stack_cas_connection {
         $this->timeout        = $settings->castimeout;
         $this->serveruserpass = $settings->serveruserpass;
         $this->debug          = $debuglog;
-        if (strpos($CFG->wwwroot, '_') !== false) {
+        if (str_contains($CFG->wwwroot, '_')) {
             $this->wwwroothasunderscores = true;
             $this->wwwrootfixupfind = str_replace('_', '\_', $CFG->wwwroot);
             $this->wwwrootfixupreplace = $CFG->wwwroot;
@@ -334,15 +334,15 @@ abstract class stack_cas_connection_base implements stack_cas_connection {
         $errorclean = [];
         foreach ($error as $err) {
             // This case arises when we use a numerical test for algebraic equivalence.
-            if (strpos($err, 'STACK: ignore previous error.') !== false) {
+            if (str_contains($err, 'STACK: ignore previous error.')) {
                 $err = '';
             }
 
-            if (strpos($err, '0 to a negative exponent') !== false) {
+            if (str_contains($err, '0 to a negative exponent')) {
                 $err = stack_string('Maxima_DivisionZero');
             }
 
-            if (strpos($err, 'args: argument must be a non-atomic expression;') !== false) {
+            if (str_contains($err, 'args: argument must be a non-atomic expression;')) {
                 $err = stack_string('Maxima_Args');
             }
 
diff --git a/stack/cas/connectorhelper.class.php b/stack/cas/connectorhelper.class.php
index 57d2030ea..796ac4eaf 100644
--- a/stack/cas/connectorhelper.class.php
+++ b/stack/cas/connectorhelper.class.php
@@ -374,7 +374,7 @@ abstract class stack_connection_helper {
             }
         }
 
-        if (strpos($debug, 'failed to load') !== false) {
+        if (str_contains($debug, 'failed to load')) {
             $message[] = stack_string('settingmaximalibraries_failed');
             $success = false;
         }
diff --git a/stack/cas/keyval.class.php b/stack/cas/keyval.class.php
index 3233f5ef6..7375538b6 100644
--- a/stack/cas/keyval.class.php
+++ b/stack/cas/keyval.class.php
@@ -109,7 +109,7 @@ class stack_cas_keyval {
         $str = str_replace('?', 'QMCHAR', $str);
 
         // CAS keyval may not contain @ outside strings.
-        if (strpos($str, '@') !== false) {
+        if (str_contains($str, '@')) {
             $this->errors[] = new $this->errclass(stack_string('illegalcaschars'), $this->context);
             $this->valid = false;
             return false;
diff --git a/stack/cas/parsingrules/201_sig_figs_validation.filter.php b/stack/cas/parsingrules/201_sig_figs_validation.filter.php
index 694fb172e..f70a5c970 100644
--- a/stack/cas/parsingrules/201_sig_figs_validation.filter.php
+++ b/stack/cas/parsingrules/201_sig_figs_validation.filter.php
@@ -63,7 +63,7 @@ class stack_ast_filter_201_sig_figs_validation implements stack_cas_astfilter_pa
 
             $pre = explode('.', $raw)[0];
             $post = '';
-            if (strpos($raw, '.') !== false) {
+            if (str_contains($raw, '.')) {
                 $post = explode('.', $raw)[1];
             }
             $min = null;
diff --git a/stack/cas/parsingrules/202_decimal_places_validation.filter.php b/stack/cas/parsingrules/202_decimal_places_validation.filter.php
index c243e6a0a..7db8adb9d 100644
--- a/stack/cas/parsingrules/202_decimal_places_validation.filter.php
+++ b/stack/cas/parsingrules/202_decimal_places_validation.filter.php
@@ -60,7 +60,7 @@ class stack_ast_filter_202_decimal_places_validation implements stack_cas_astfil
             $raw = explode('e', $raw)[0];
 
             $post = '';
-            if (strpos($raw, '.') !== false) {
+            if (str_contains($raw, '.')) {
                 $post = explode('.', $raw)[1];
             }
             if ($this->min !== null && $this->min > 0) {
diff --git a/stack/cas/parsingrules/450_split_floats.filter.php b/stack/cas/parsingrules/450_split_floats.filter.php
index 1136aa73b..ed4430d1e 100644
--- a/stack/cas/parsingrules/450_split_floats.filter.php
+++ b/stack/cas/parsingrules/450_split_floats.filter.php
@@ -31,9 +31,9 @@ class stack_ast_filter_450_split_floats implements stack_cas_astfilter_exclusion
         $process = function($node) use (&$answernotes) {
             if ($node instanceof MP_Float && $node->raw !== null) {
                 $replacement = false;
-                if (strpos($node->raw, 'e') !== false) {
+                if (str_contains($node->raw, 'e')) {
                     $parts = explode('e', $node->raw);
-                    if (strpos($parts[0], '.') !== false) {
+                    if (str_contains($parts[0], '.')) {
                         $replacement = new MP_Operation('*', new MP_Float(floatval($parts[0]), $parts[0]),
                                 new MP_Operation('*', new MP_Identifier('e'), new MP_Integer(intval($parts[1]))));
                     } else {
@@ -49,9 +49,9 @@ class stack_ast_filter_450_split_floats implements stack_cas_astfilter_exclusion
                                 new MP_Identifier('e')), new MP_Integer($val));
                         $replacement->lhs->position['insertstars'] = true;
                     }
-                } else if (strpos($node->raw, 'E') !== false) {
+                } else if (str_contains($node->raw, 'E')) {
                     $parts = explode('E', $node->raw);
-                    if (strpos($parts[0], '.') !== false) {
+                    if (str_contains($parts[0], '.')) {
                         $replacement = new MP_Operation('*', new MP_Float(floatval($parts[0]), $parts[0]),
                                 new MP_Operation('*', new MP_Identifier('E'), new MP_Integer(intval($parts[1]))));
                     } else {
diff --git a/stack/cas/parsingrules/801_singleton_numeric.filter.php b/stack/cas/parsingrules/801_singleton_numeric.filter.php
index 8fa4502e8..7f169279f 100644
--- a/stack/cas/parsingrules/801_singleton_numeric.filter.php
+++ b/stack/cas/parsingrules/801_singleton_numeric.filter.php
@@ -73,7 +73,7 @@ class stack_ast_filter_801_singleton_numeric implements stack_cas_astfilter_para
             if ($this->float) {
                 // Turn floats that are to small or large to powers of ten.
                 $p = 0;
-                if (strpos($node->toString(), 'E') !== false) {
+                if (str_contains($node->toString(), 'E')) {
                     $p = intval(explode('E', $node->toString())[1]);
                 }
 
@@ -279,12 +279,12 @@ class stack_ast_filter_801_singleton_numeric implements stack_cas_astfilter_para
     public function float_to_power(MP_Float $float): MP_Node {
         $raw = strtolower($float->raw);
         $p = 0;
-        if (strpos($raw, 'e') !== false) {
+        if (str_contains($raw, 'e')) {
             $parts = explode('e', $raw);
             $raw = $parts[0];
             $p = intval($parts[1]);
         }
-        if (strpos($raw, '.') !== false) {
+        if (str_contains($raw, '.')) {
             $parts = explode('.', $raw);
             $raw = $parts[0] . $parts[1];
             $p = $p - strlen($parts[1]);
diff --git a/stack/cas/parsingrules/802_singleton_units.filter.php b/stack/cas/parsingrules/802_singleton_units.filter.php
index 27d0d1138..a7467ad02 100644
--- a/stack/cas/parsingrules/802_singleton_units.filter.php
+++ b/stack/cas/parsingrules/802_singleton_units.filter.php
@@ -201,7 +201,7 @@ class stack_ast_filter_802_singleton_units implements stack_cas_astfilter_parame
 
         // Check floats and fix if need be.
         foreach ($floats as $node) {
-            if ((strpos($node->toString(), 'E') !== false || $this->floattopower) && $node->raw !== null) {
+            if ((str_contains($node->toString(), 'E') || $this->floattopower) && $node->raw !== null) {
                 $p = 0;
                 $parts = explode('E', $node->toString());
                 $p = intval($parts[1]);
diff --git a/stack/cas/parsingrules/910_inert_float_for_display.filter.php b/stack/cas/parsingrules/910_inert_float_for_display.filter.php
index b6413e654..29a1169b2 100644
--- a/stack/cas/parsingrules/910_inert_float_for_display.filter.php
+++ b/stack/cas/parsingrules/910_inert_float_for_display.filter.php
@@ -47,7 +47,7 @@ class stack_ast_filter_910_inert_float_for_display implements stack_cas_astfilte
                     return true;
                 }
                 $dp = 0;
-                if (strpos($raw, '.') !== false) {
+                if (str_contains($raw, '.')) {
                     $parts = explode('.', $raw);
                     $dp = strlen(explode('e', $parts[1])[0]);
                 }
diff --git a/stack/input/dropdown/dropdown.class.php b/stack/input/dropdown/dropdown.class.php
index 6c33c26ce..df5bd5caa 100644
--- a/stack/input/dropdown/dropdown.class.php
+++ b/stack/input/dropdown/dropdown.class.php
@@ -176,7 +176,7 @@ class stack_dropdown_input extends stack_input {
             if (is_array($value)) {
                 // Inject strings back if they exist.
                 foreach ($value as $key => $something) {
-                    if (strpos($something, '[STR:') !== false) {
+                    if (str_contains($something, '[STR:')) {
                         foreach ($strings as $skey => $string) {
                             $value[$key] = str_replace("[STR:$skey]", '"' . $string . '"', $value[$key]);
                         }
diff --git a/stack/maximaparser/corrective_parser.php b/stack/maximaparser/corrective_parser.php
index 8865e46d4..c79d6c7df 100644
--- a/stack/maximaparser/corrective_parser.php
+++ b/stack/maximaparser/corrective_parser.php
@@ -79,9 +79,9 @@ class maxima_corrective_parser {
         $stringles = str_replace(array_keys($letters), array_values($letters), $stringles);
 
         // Check for all three of . and , and ; which must indicate inconsistency.
-        if (strpos($stringles, '.') !== false &&
-            strpos($stringles, ',') !== false &&
-            strpos($stringles, ';') !== false) {
+        if (str_contains($stringles, '.') &&
+            str_contains($stringles, ',') &&
+            str_contains($stringles, ';')) {
                 $errors[] = stack_string('stackCas_decimal_usedthreesep');
         }
         $decimals = '.';
@@ -90,7 +90,7 @@ class maxima_corrective_parser {
         }
         if ($decimals == ',') {
             // Clearly there is a lot more work to do here to get this all to work!
-            if (strpos($stringles, '.') !== false) {
+            if (str_contains($stringles, '.')) {
                 $answernote[] = 'forbiddenCharDecimal';
                 $errors[] = stack_string('stackCas_decimal_usedcomma');
                 return null;
@@ -188,7 +188,7 @@ class maxima_corrective_parser {
         $stringles = trim($stringles);
         $stringles = preg_replace('!\s+!', ' ', $stringles);
 
-        if (strpos($stringles, ' ') !== false) {
+        if (str_contains($stringles, ' ')) {
             // Special cases: allow students to type in expressions such as "x>1 and x<4".
             foreach ($safespacepatterns as $key => $pat) {
                 $stringles = str_replace($key, $pat, $stringles);
@@ -449,7 +449,7 @@ class maxima_corrective_parser {
             $cmds = str_replace('@@Is@@', '[[syntaxexamplehighlight]_[syntaxexamplehighlight]]', $cmds);
             $answernote[] = 'spaces';
             $errors[] = stack_string('stackCas_spaces', ['expr' => stack_maxima_format_casstring($cmds)]);
-        } else if ($foundchar === ':' && (strpos($string, ':lisp') !== false)) {
+        } else if ($foundchar === ':' && (str_contains($string, ':lisp'))) {
             $errors[] = stack_string('stackCas_forbiddenWord',
                     ['forbid' => stack_maxima_format_casstring('lisp')]);
             $answernote[] = 'forbiddenWord';
diff --git a/stack/prt.evaluatable.class.php b/stack/prt.evaluatable.class.php
index 3c4a077f0..37152a5c6 100644
--- a/stack/prt.evaluatable.class.php
+++ b/stack/prt.evaluatable.class.php
@@ -271,7 +271,7 @@ class prt_evaluatable implements cas_raw_value_extractor {
     public function get_fverrors($format='strings') {
         $err = [];
         foreach ($this->errors as $er) {
-            if (strpos($er->get_context(), '/fv') !== false) {
+            if (str_contains($er->get_context(), '/fv')) {
                 if ($format === 'strings') {
                     $err[] = $er->get_legacy_error();
                 } else {
diff --git a/stack/questionreport.class.php b/stack/questionreport.class.php
index f762fbf8f..2e52f26f1 100644
--- a/stack/questionreport.class.php
+++ b/stack/questionreport.class.php
@@ -292,13 +292,13 @@ class stack_question_report {
                             // Tidy up inputs by (i) trimming status and whitespace, and (2) removing input name.
                             $datas = trim(substr($data, strlen($input . ':')));
                             $status = 'other';
-                            if (strpos($datas, '[score]') !== false) {
+                            if (str_contains($datas, '[score]')) {
                                 $status = 'score';
                                 $datas = trim(substr($datas, 0, -7));
-                            } else if (strpos($datas, '[valid]') !== false) {
+                            } else if (str_contains($datas, '[valid]')) {
                                 $status = 'valid';
                                 $datas = trim(substr($datas, 0, -7));
-                            } else if (strpos($datas, '[invalid]') !== false) {
+                            } else if (str_contains($datas, '[invalid]')) {
                                 $status = 'invalid';
                                 $datas = trim(substr($datas, 0, -9));
                             }
diff --git a/stack/utils.class.php b/stack/utils.class.php
index 906293b0e..53f162ccd 100644
--- a/stack/utils.class.php
+++ b/stack/utils.class.php
@@ -181,7 +181,7 @@ class stack_utils {
         $length = strlen($string);
         for ($i = 0; $i < $length; $i++) {
             $char = $string[$i];
-            if (strpos($lefts, $char) !== false) {
+            if (str_contains($lefts, $char)) {
                 array_push($openstack, $char);
 
             } else if (($closerpos = strpos($rights, $char)) !== false) {
@@ -828,9 +828,9 @@ class stack_utils {
      */
     public static function maxima_translate_string(string $string) {
         $fixed = $string;
-        if (strpos($string, '0 to a negative exponent') !== false) {
+        if (str_contains($string, '0 to a negative exponent')) {
             $fixed = stack_string('Maxima_DivisionZero');
-        } else if (strpos($string, 'args: argument must be a non-atomic expression;') !== false) {
+        } else if (str_contains($string, 'args: argument must be a non-atomic expression;')) {
             $fixed = stack_string('Maxima_Args');
         }
         return $fixed;
diff --git a/tests/cassession2_test.php b/tests/cassession2_test.php
index 0481d095c..1cec9631b 100644
--- a/tests/cassession2_test.php
+++ b/tests/cassession2_test.php
@@ -2190,7 +2190,7 @@ class cassession2_test extends qtype_stack_testcase {
         $at1->instantiate();
 
         $actual = $s1[0]->get_dispvalue();
-        if (strpos($actual, 'quantile_gamma(') !== false) {
+        if (str_contains($actual, 'quantile_gamma(')) {
             // Seems that the distrib package is not available. Skip this test.
             $this->markTestSkipped('Skipping because it seems the distrib package is not installed.');
         }
diff --git a/tests/fixtures/test_base.php b/tests/fixtures/test_base.php
index 4ab3f6fd1..c4b3a9524 100644
--- a/tests/fixtures/test_base.php
+++ b/tests/fixtures/test_base.php
@@ -180,7 +180,7 @@ abstract class qtype_stack_testcase extends advanced_testcase {
             function(array $matches): string {
                 $decimals = strlen(explode('.', $matches[1])[1] ?? '') ?: 0;
                 $fixedbase = sprintf("%.{$decimals}E", (float)$matches[0]);
-                return strpos($matches[2], '+') !== false ? $fixedbase : str_replace('+', '', $fixedbase);
+                return str_contains($matches[2], '+') ? $fixedbase : str_replace('+', '', $fixedbase);
             },
             $content
         );
@@ -317,7 +317,7 @@ abstract class qtype_stack_walkthrough_test_base extends \qbehaviour_walkthrough
         $question = $this->quba->get_question($this->slot);
         $attempt  = $this->quba->get_question_attempt($this->slot);
         $qs = $attempt->get_last_step();
-        $this->assertTrue((strpos($qs->get_new_response_summary(), $note) !== false));
+        $this->assertTrue(str_contains($qs->get_new_response_summary(), $note));
     }
 
     protected function check_output_contains_text_input($name, $value = null, $enabled = true) {
diff --git a/vle_specific.php b/vle_specific.php
index 54e22ea67..311fcbcb0 100644
--- a/vle_specific.php
+++ b/vle_specific.php
@@ -277,7 +277,7 @@ function stack_fetch_included_content(string $url) {
     if (strpos($lc, 'http://') === 0 || strpos($lc, 'https://') === 0) {
         $good = true;
     } else {
-        if (strpos($path, '..') !== false || strpos($path, '/') === 0 || strpos($path, '~') === 0) {
+        if (str_contains($path, '..') || strpos($path, '/') === 0 || strpos($path, '~') === 0) {
             $error = 'Traversing the directory tree is forbidden.';
             $good = false;
             return false;
-- 
GitLab