PHP错误:未定义的偏移量:10

时间:2012-09-21 16:51:53

标签: php arrays forms debugging loops

我写了一个基于用户输入创建拼图的程序。有一个html表单接受用户的单词并将它们发布到php程序。然后php程序创建拼图并打印出来。

有一个现场演示here。你可以输入你自己的单词。

它看起来不错但是当我在本地服务器上运行它并启用了php错误提示时,我看到错误消息说Undefined offset: 10 at line 147 and 148。从if ($board[$curr_row][$curr_col] == '.'开始的PHP代码行生成错误...您可以使用Ctrl + F查找代码。我不明白如何在$curr_col$curr_row中获得10,因为循环应该在达到9之后停止。

请帮助我了解循环在达到10之后如何运行,非常感谢!

该程序的压缩版本为here

以下是php的代码:

<html>
    <body>
        <?php

        /* word Find
         Generates a word search puzzle based on a word list entered by user.
         User can also specify the size of the puzzle and print out
         an answer key if desired
         */
        //If there is no data from the form, prompt the user to go back
        if (!filter_has_var(INPUT_POST, "puzzle_name")) {
            print <<<MUL_LINE
    <!DOCTYPE html>
<html >
    <head>
        <title>Oops!</title>
    </head>

    <body>
        <p>This page should not be called directly, please visit 
        the <a href="./form.html">puzzle form</a> to continue.</p>
    </body>
</html>

MUL_LINE;
        } else {
            $boardData = array("name" => filter_input(INPUT_POST, "puzzle_name"), "width" => filter_input(INPUT_POST, "grid_width"), "height" => filter_input(INPUT_POST, "grid_height"));

            if (parseList() == TRUE) {//parse the word list in textarea to an array of words
                //keep trying to fill the board untill a valid puzzle is made
                do {
                    clearBoard();
                    //reset the board
                    $pass = fillBoard();
                } while($pass == FALSE);
                printBoard();
                //if the board if successfully filled, print the puzzle
            }
        }//end word list exists if

        //parse the word list in textarea to an array of words
        function parseList() {
            //get word list, creates array of words from it
            //or return false if impossible

            global $word, $wordList, $boardData;

            $wordList = filter_input(INPUT_POST, "wordList");
            $itWorked = TRUE;

            //convert word list entirely to upper case
            $wordList = strtoupper($wordList);

            //split word list into array
            $word = explode("\n", $wordList);
            //an array of words

            foreach ($word as $key => $currentWord) {
                //trim all the beginning and trailer spaces
                $currentWord = rtrim(ltrim($currentWord));

                //stop if any words are too long to fit in puzzle
                if ((strlen($currentWord) > $boardData["width"]) && (strlen($currentWord) > $boardData["height"])) {
                    print "$currentWord is too long for puzzle";
                    $itWorked = FALSE;
                }//end if
                $word[$key] = $currentWord;
            }//end foreach
            return $itWorked;
        }//end parseList

        //reset the board by filling each cell with "."
        function clearBoard() {
            //initialize board with a . in each cell
            global $board, $boardData;

            for ($row = 0; $row < $boardData["height"]; $row++) {
                for ($col = 0; $col < $boardData["width"]; $col++) {
                    $board[$row][$col] = ".";
                }//end col for loop
            }//end row for loop
        }//end clearBoard

        //fill the board
        function fillBoard() {
            global $word;
            $pass = FALSE;
            //control the loop of filling words, false will stop the loop
            //control the loop, if all the words are filled, the counter will be as equal to the number
            //of elements in array $words, thus the loop stops successfully
            $counter = 0;

            do {

                $pass = fillWord($word[$counter]);
                //if a word is filled, $pass is set to true
                $counter++;

            }
            //if a word can't be filled, pass==FALSE and loop stops
            //or if all words are through, loop stops
            while($pass==TRUE && $counter<count($word));

            //return TRUE if all filled successfully, FALSE if not
            if ($pass == TRUE && $counter == count($word)) {
                return TRUE;
            } else {
                return FALSE;
            }
        }

        //function used to fill  a single word
        function fillWord($single_word) {
            global $board, $boardData;
            //the direction of how the word will be filled, 50% chance to be H, and 50% chance to be V
            $dir = (rand(0, 1) == 0 ? "H" : "V");
            //H(horizontal) means fill the word from left to right
            //V(vertical) means fill the word from up to down
            //loop control. if a letter is not filled, $pass is set to false and loop stops
            $pass = TRUE;
            //loop control. if all letters are filled successfully, loop stops too.
            $counter = 0;

            //decide the cell to fill the first word. the cell is located at $board[$curr_row][$curr_col]
            if ($dir == "H") {//if the word will be fileld from left to right
                $curr_row = rand(0, $boardData["height"] - 1);
                //pick up a random row of the 10 rows ( rand(0,9) )
                $curr_col = rand(0, ($boardData["width"] - ( strlen($single_word - 1)) - 1));
                //pick up a random column of fillable columns
                //if the word is "banana" and the board's width
                //is 10, the starting column can only be rand(0, 4)
            } else if ($dir == "V") {//if the word will be fileld from up to down
                $curr_row = rand(0, ($boardData["height"] - ( strlen($single_word - 1)) - 1));
                $curr_col = rand(0, $boardData["width"] - 1);
            } else {
                print "invalid direction";
            }

            //the loop that keeps trying to fill letters of the word
            while ($pass && ($counter < strlen($single_word))) {//while the $pass is true AND there are still letters

                //to fill, keep the loop going

                //the next line and the line after generate the msg "Undefined offset: 10",
                //$curr_row and $curr_col should never be 10 because the loop should be stopped
                //if the last letter of the word is filled
                if ($board[$curr_row][$curr_col] == '.' || //if the cell is not filled, reset fillboard() to "."
                $board[$curr_row][$curr_col] == substr($single_word, $counter, 1))//or it has already been filled with the same letter
                {
                    $board[$curr_row][$curr_col] = substr($single_word, $counter, 1);
                    // write/fill the letter in the cell
                    $counter++;
                    if ($dir == "H") {
                        $curr_col++;
                        //next column, move to the next right cell
                    } else if ($dir == "V") {
                        $curr_row++;
                        //next row, move to the next lower cell
                    } else {
                        print "\nHuge direction error!";
                    }

                } else {
                    $pass = FALSE;
                    // failed to fill a letter, stop the loop
                }
            }
            //if all the letters are filled successfully, the single word is filled successfully
            //return true, let $fillBoard go filling next single word
            if ($pass && ($counter == strlen($single_word))) {
                /* for debug purpose
                 print "<hr />";print "<p>TRUE</p>";print "<hr />";
                 print $single_word;
                 print $curr_row . "," . $curr_col . "<br />";
                 print "<hr />";*/

                return TRUE;
            } else {
                //failed to fill the word, reset the board and start all over again
                return FALSE;
            }

        }//end function fillWord

        //print the successful filled puzzle
        function printBoard() {
            global $board;
            print <<<MULLINE
    <style type="text/css">
    table, td{
        border: 1px solid black;
    }

    </style>
MULLINE;
            print '<table >';
            foreach ($board as $row) {
                print '<tr>';
                foreach ($row as $cell) {
                    print '<td>';
                    print $cell;
                    print '</td>';

                }
                print("<br />");
                print '</tr>';
            }
            print "</table>";
        }
        ?>
    </body>
</html>

1 个答案:

答案 0 :(得分:2)

我不认为以下代码片段是正确的。

strlen($single_word - 1)

位于以下行:

$curr_col = rand(0, ($boardData["width"] - ( strlen($single_word - 1)) - 1));

$curr_row = rand(0, ($boardData["height"] - ( strlen($single_word - 1)) - 1));

它会将单词转换为整数。从该数字中减去一个。然后将其转换回字符串并获取长度。所以你有一个长度的垃圾值。