0

So first off my database table is set up like this:

id | affsub | offer_name | date | time | payout

1 | stringhere | offer | 2017-09-12 | 06:47:00 | 1

and I want to to echo out all the rows that include the affsub stringhere into a html table. I have tried this:

<?php
   $id = $get_info_id;
   $mysqli = new \mysqli('localhost', 'user', 'pass', 'db');
   $aff = $mysqli->query("SELECT affsub FROM users WHERE id = $id")->fetch_object()->affsub;
   $affsub = $aff;
   $userinfo= $mysqli->query("SELECT offer_name, time, payout FROM conversions WHERE affsub = ". $affsub . "");

  if ($userinfo->num_rows > 0) {
     while($row = $userinfo->fetch_assoc()) {
        echo '<tr>
           <td><b><color=black>' .$row['offer_name'].' </b></td>
           <td><color=black>' .$row['time'].'</td>
           <td>$<color=black>' .$row['payout'].'</td>
        </tr>';
     }
  }
  else {
     echo "<b><center>No Conversions Have Happened.</center></b>";
  }
?>

and I know that it is getting the affsub because if i do echo $affsub my affsub is echoed out but nothing is shown on the table and im not sure whats happening.

awesomexbox3
  • 37
  • 1
  • 11
  • You're trying to use the results of a query as a where clause in another query? $userinfo= $mysqli->query("SELECT offer_name, time, payout FROM conversions WHERE affsub = ". $affsub . ""); – Difster Jul 13 '17 at 23:24
  • yes because i want to use the id of the user and find the users affsub from another table and use it for this table – awesomexbox3 Jul 13 '17 at 23:26
  • are you sure the second query got result ? – Accountant م Jul 13 '17 at 23:28
  • You have SQL injection vulnerabilities, as well as on the HTML side. Use prepared/parameterized queries. Use `htmlspecialchars()` when echoing arbitrary data into an HTML context. – Brad Jul 13 '17 at 23:28
  • the first query got a result because i echoed $affsub but the second query is the one im not sure about – awesomexbox3 Jul 13 '17 at 23:29
  • Your'e trying to echo an object in to the second query. That's not going to work. – Difster Jul 13 '17 at 23:29
  • You need quotes inside string around `$affsub`. Since you use double quotes for string (which parses variables) you may add single qoutes inside without concatenation like this: `$mysqli->query("SELECT ... '$affsub'");` + SQL injection warning. – shudder Jul 13 '17 at 23:29
  • where are the vulnerabilities? – awesomexbox3 Jul 13 '17 at 23:30
  • @shudder that did it but now im worried about the vulnerabilities how do i fix that? – awesomexbox3 Jul 13 '17 at 23:31
  • @awesomexbox3 Well then you need to make sure if the second query get results or not, please add this line after the second query `var_dump($userinfo);exit;` . also you need to [switch to prepared statements](https://stackoverflow.com/questions/45031956/switching-to-prepared-statements/45034865) – Accountant م Jul 13 '17 at 23:32
  • 1
    @Accountantم i fixed the issue but now how do i fix the sql injection vulnerability? – awesomexbox3 Jul 13 '17 at 23:33
  • Prepared statements will protect you from having user provided data interfere with your queries by becoming part of them (and then nasty things can happen). – shudder Jul 13 '17 at 23:35
  • @awesomexbox3 prepared statements will protect you from SQL injection attack.Please check this question [https://stackoverflow.com/questions/60174/how-can-i-prevent-sql-injection-in-php](https://stackoverflow.com/questions/60174/how-can-i-prevent-sql-injection-in-php) – Accountant م Jul 13 '17 at 23:36
  • wait how would it cause an sql attack since im not putting any information into the database but im pulling stuff from it? – awesomexbox3 Jul 13 '17 at 23:38
  • Please tell us if the two tables are in a foreign key relation. I mean please provide the columns of `conversions` too. –  Jul 13 '17 at 23:46
  • About your last question to @Accountantم : Indeed, your code just pulls data from db. But a hacker could pull all the data from all the databases from all the tables of yours :-) Plus, if you are preserving some data about your systems, like some paths of your file system(s), in the database, then the hacker will manage to pull all your data from all your systems too :-) –  Jul 13 '17 at 23:53
  • hm ok but how would i protect the code? i added .mysqli_real_escape_string($mysqli, $row['offer_name']).' to it, is that a prepared statement? – awesomexbox3 Jul 14 '17 at 00:03
  • No, it's not. I will make a complete example with prepared statements and exception handling for you and I'll post it as an answer. It will take some time, and it's late now, but tomorrow you'll have it. –  Jul 14 '17 at 00:07
  • ok thanks i will mark it as correct it too – awesomexbox3 Jul 14 '17 at 00:07
  • 1
    No need, but thanks. I post it as an answer just because you need an example and because this is the best way for you to see the code. So don't accept it. Anyway, please post the columns of `conversions` table too. –  Jul 14 '17 at 00:10
  • 1
    No, that is called escaping the parameters. it protects you from SQL injection attacks if you used the correct database encoding. but we as human beings are usually going to forget escaping something. this [question](https://stackoverflow.com/questions/45031956/switching-to-prepared-statements) is about switching to prepared statements. search on the topic and wait for @aendeerei example tomorrow – Accountant م Jul 14 '17 at 00:13
  • id, affsub, offer_name, date, time, payout – awesomexbox3 Jul 14 '17 at 00:13

3 Answers3

0

You should simply join the two queries:

$userinfo = $mysql->query("SELECT c.offer_name, c.time, c.payout
    FROM conversations AS c
    JOIN users AS u ON u.affsub = c.affsub
    WHERE u.id = $id");
Barmar
  • 741,623
  • 53
  • 500
  • 612
0

I think the issue is that you are missing the inverted commas for the search term in the WHERE clause. It should look like this affsub = '$affsub' .

Try this.

$userinfo= $mysqli->query("SELECT offer_name, time, payout FROM conversions WHERE affsub = '$affsub' ");
blokeish
  • 571
  • 5
  • 9
0

Please note that the credits for the sql statement that I used belong to @Barmar, because he had yesterday the idea of the joined queries first.

Now, down under are the two methods to use. Notice that I didn't use any OOP or functions. The reason is that I wanted you to have a compact view of all steps.


How to use mysqli prepared statements and exception handling

1. Use get_result() + fetch_object() or fetch_array() or fetch_all():

This method (recommended) works only if the driver mysqlnd (MySQL Native Driver) is installed/activated. I think the driver is by default activated in PHP >= 5.3. Implement the code and let it run. It should work. If it works, then it's perfect. If not, try to activate mysqlnd driver, e.g. uncomment extension=php_mysqli_mysqlnd.dll in php.ini. Otherwise you must use the second method (2).

<?php
/*
 * Define constants for db connection.
 */
define('MYSQL_HOST', '...');
define('MYSQL_PORT', '...');
define('MYSQL_DATABASE', '...');
define('MYSQL_CHARSET', 'utf8');
define('MYSQL_USERNAME', '...');
define('MYSQL_PASSWORD', '...');

/*
 * Activate PHP error reporting.
 * Use ONLY on development code, NEVER on production code!!!
 * ALWAYS resolve WARNINGS and ERRORS.
 * I recommend to always resolve NOTICES too.
 */
error_reporting(E_ALL);
ini_set('display_errors', 1);

/*
 * Enable internal report functions. This enables the exception handling, 
 * e.g. mysqli will not throw PHP warnings anymore, but mysqli exceptions 
 * (mysqli_sql_exception). They are catched in the try-catch block.
 * 
 * MYSQLI_REPORT_ERROR: Report errors from mysqli function calls.
 * MYSQLI_REPORT_STRICT: Throw a mysqli_sql_exception for errors instead of warnings. 
 * 
 * See:
 *      http://php.net/manual/en/class.mysqli-driver.php
 *      http://php.net/manual/en/mysqli-driver.report-mode.php
 *      http://php.net/manual/en/mysqli.constants.php
 */
$mysqliDriver = new mysqli_driver();
$mysqliDriver->report_mode = (MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);

try {
    // To delete (just for test here).
    $get_info_id = 1;

    $userId = $get_info_id;
    $fetchedData = array();

    /*
     * Create the db connection.
     * 
     * Throws mysqli_sql_exception.
     * See: http://php.net/manual/en/mysqli.construct.php
     */
    $connection = new mysqli(
            MYSQL_HOST
            , MYSQL_USERNAME
            , MYSQL_PASSWORD
            , MYSQL_DATABASE
            , MYSQL_PORT
    );
    if ($connection->connect_error) {
        throw new Exception('Connect error: ' . $connection->connect_errno . ' - ' . $connection->connect_error);
    }

    /*
     * The SQL statement to be prepared. Notice the so-called markers, 
     * e.g. the "?" signs. They will be replaced later with the 
     * corresponding values when using mysqli_stmt::bind_param.
     * 
     * See: http://php.net/manual/en/mysqli.prepare.php
     */
    $sql = 'SELECT 
                cnv.offer_name, 
                cnv.time, 
                cnv.payout 
            FROM conversions AS cnv
            LEFT JOIN users AS usr ON usr.affsub = cnv.affsub 
            WHERE usr.id = ?';

    /*
     * Prepare the SQL statement for execution.
     * 
     * Throws mysqli_sql_exception.
     * See: http://php.net/manual/en/mysqli.prepare.php
     */
    $statement = $connection->prepare($sql);
    if (!$statement) {
        throw new Exception('Prepare error: ' . $connection->errno . ' - ' . $connection->error);
    }

    /*
     * Bind variables for the parameter markers (?) in the 
     * SQL statement that was passed to mysqli::prepare. The first 
     * argument of mysqli_stmt::bind_param is a string that contains one 
     * or more characters which specify the types for the corresponding bind variables.
     * 
     * See: http://php.net/manual/en/mysqli-stmt.bind-param.php
     */
    $bound = $statement->bind_param('i', $userId);
    if (!$bound) {
        throw new Exception('Bind error: The variables could not be bound to the prepared statement');
    }

    /*
     * Execute the prepared SQL statement.
     * When executed any parameter markers which exist will 
     * automatically be replaced with the appropriate data.
     * 
     * See: http://php.net/manual/en/mysqli-stmt.execute.php
     */
    $executed = $statement->execute();
    if (!$executed) {
        throw new Exception('Execute error: The prepared statement could not be executed!');
    }

    /*
     * Get the result set from the prepared statement. In case of 
     * failure use errno, error and/or error_list to see the error.
     * 
     * NOTA BENE:
     * Available only with mysqlnd ("MySQL Native Driver")! If this 
     * is not installed, then uncomment "extension=php_mysqli_mysqlnd.dll" in 
     * PHP config file (php.ini) and restart web server (I assume Apache) and 
     * mysql service. Or use the following functions instead:
     * mysqli_stmt::store_result + mysqli_stmt::bind_result + mysqli_stmt::fetch.
     * 
     * See:
     *      http://php.net/manual/en/mysqli-stmt.get-result.php
     *      https://stackoverflow.com/questions/8321096/call-to-undefined-method-mysqli-stmtget-result
     */
    $result = $statement->get_result();
    if (!$result) {
        throw new Exception('Get result error: ' . $connection->errno . ' - ' . $connection->error);
    }

    /*
     * Get the number of rows in the result.
     * 
     * See: http://php.net/manual/en/mysqli-result.num-rows.php
     */
    $numberOfRows = $result->num_rows;

    /*
     * Fetch data and save it into $fetchedData array.
     * 
     * See: http://php.net/manual/en/mysqli-result.fetch-array.php
     */
    if ($numberOfRows > 0) {
        /*
         * Use mysqli_result::fetch_object to fetch a row - as object - 
         * at a time. E.g. use it in a loop construct like 'while'.
         */
        while ($row = $result->fetch_object()) {
            $fetchedData[] = $row;
        }
    }

    /*
     * Free the memory associated with the result. You should 
     * always free your result when it is not needed anymore.
     * 
     * See: http://php.net/manual/en/mysqli-result.free.php
     */
    $result->close();

    /*
     * Close the prepared statement. It also deallocates the statement handle.
     * If the statement has pending or unread results, it cancels them 
     * so that the next query can be executed.
     * 
     * See: http://php.net/manual/en/mysqli-stmt.close.php
     */
    $statementClosed = $statement->close();
    if (!$statementClosed) {
        throw new Exception('The prepared statement could not be closed!');
    }

    // Close db connection.
    $connectionClosed = $connection->close();
    if (!$connectionClosed) {
        throw new Exception('The db connection could not be closed!');
    }
} catch (mysqli_sql_exception $e) {
    echo 'Error: ' . $e->getCode() . ' - ' . $e->getMessage();
    exit();
} catch (Exception $e) {
    echo $e->getMessage();
    exit();
}

/*
 * Disable internal report functions.
 * 
 * MYSQLI_REPORT_OFF: Turns reporting off.
 * 
 * See:
 *      http://php.net/manual/en/class.mysqli-driver.php
 *      http://php.net/manual/en/mysqli-driver.report-mode.php
 *      http://php.net/manual/en/mysqli.constants.php
 */
$mysqliDriver->report_mode = MYSQLI_REPORT_OFF;
?>

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>Example code: Mysqli prepared statements & exception handling</title>
    </head>
    <style>
        table {
            font-family: "Verdana", Arial, sans-serif;
            font-size: 14px;
            border-collapse: collapse;
        }

        table, th, td {
            border: 1px solid #ccc;
        }

        th, td {
            padding: 7px;
        }

        thead {
            color: #fff;
            font-weight: normal;
            background-color: coral;
        }

        tfoot {
            background-color: wheat;
        }

        tfoot td {
            text-align: right;
        }
    </style>
    <body>

        <?php
        $countOfFetchedData = count($fetchedData);

        if ($countOfFetchedData > 0) {
            ?>
            <table>
                <thead>
                    <tr>
                        <th>Crt. No.</th>
                        <th>OFFER NAME</th>
                        <th>TIME</th>
                        <th>PAYOUT</th>
                    </tr>
                </thead>
                <tbody>
                    <?php
                    foreach ($fetchedData as $key => $item) {
                        $offerName = $item->offer_name;
                        $time = $item->time;
                        $payout = $item->payout;
                        ?>
                        <tr>
                            <td><?php echo $key + 1; ?></td>
                            <td><?php echo $offerName; ?></td>
                            <td><?php echo $time; ?></td>
                            <td><?php echo $payout; ?></td>
                        </tr>
                        <?php
                    }
                    ?>
                </tbody>
                <tfoot>
                    <tr>
                        <td colspan="7">
                            - <?php echo $countOfFetchedData; ?> records found -
                        </td>
                    </tr>
                </tfoot>
            </table>
            <?php
        } else {
            ?>
            <span>
                No records found.
            </span>
            <?php
        }
        ?>

    </body>
</html>

NB: How to use fetch_array() instead of fetch_object():

//...
if ($numberOfRows > 0) {
    /*
     * Use mysqli_result::fetch_array to fetch a row at a time.
     * e.g. use it in a loop construct like 'while'.
     */
    while ($row = $result->fetch_array(MYSQLI_ASSOC)) {
        $fetchedData[] = $row;
    }
}
//...

Make the corresponding changes in the html code too.

NB: How to use fetch_all() instead of fetch_object():

//...
if ($numberOfRows > 0) {
    /*
     * Use mysqli_result::fetch_all to fetch all rows at once.
     */
    $fetchedData = $result->fetch_all(MYSQLI_ASSOC);
}
//...

Make the corresponding changes in the html code too.

2. Use store_result() + bind_result() + fetch():

Works without the driver mysqlnd (MySQL Native Driver).

<?php
/*
 * Define constants for db connection.
 */
define('MYSQL_HOST', '...');
define('MYSQL_PORT', '...');
define('MYSQL_DATABASE', '...');
define('MYSQL_CHARSET', 'utf8');
define('MYSQL_USERNAME', '...');
define('MYSQL_PASSWORD', '...');

/*
 * Activate PHP error reporting.
 * Use ONLY on development code, NEVER on production code!!!
 * ALWAYS resolve WARNINGS and ERRORS.
 * I recommend to always resolve NOTICES too.
 */
error_reporting(E_ALL);
ini_set('display_errors', 1);

/*
 * Enable internal report functions. This enables the exception handling, 
 * e.g. mysqli will not throw PHP warnings anymore, but mysqli exceptions 
 * (mysqli_sql_exception). They are catched in the try-catch block.
 * 
 * MYSQLI_REPORT_ERROR: Report errors from mysqli function calls.
 * MYSQLI_REPORT_STRICT: Throw a mysqli_sql_exception for errors instead of warnings. 
 * 
 * See:
 *      http://php.net/manual/en/class.mysqli-driver.php
 *      http://php.net/manual/en/mysqli-driver.report-mode.php
 *      http://php.net/manual/en/mysqli.constants.php
 */
$mysqliDriver = new mysqli_driver();
$mysqliDriver->report_mode = (MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);

try {
    // To delete (just for test here).
    $get_info_id = 1;

    $userId = $get_info_id;
    $fetchedData = array();

    /*
     * Create the db connection.
     * 
     * Throws mysqli_sql_exception.
     * See: http://php.net/manual/en/mysqli.construct.php
     */
    $connection = new mysqli(
            MYSQL_HOST
            , MYSQL_USERNAME
            , MYSQL_PASSWORD
            , MYSQL_DATABASE
            , MYSQL_PORT
    );
    if ($connection->connect_error) {
        throw new Exception('Connect error: ' . $connection->connect_errno . ' - ' . $connection->connect_error);
    }

    /*
     * The SQL statement to be prepared. Notice the so-called markers, 
     * e.g. the "?" signs. They will be replaced later with the 
     * corresponding values when using mysqli_stmt::bind_param.
     * 
     * See: http://php.net/manual/en/mysqli.prepare.php
     */
    $sql = 'SELECT 
                cnv.offer_name, 
                cnv.time, 
                cnv.payout 
            FROM conversions AS cnv
            LEFT JOIN users AS usr ON usr.affsub = cnv.affsub 
            WHERE usr.id = ?';

    /*
     * Prepare the SQL statement for execution.
     * 
     * Throws mysqli_sql_exception.
     * See: http://php.net/manual/en/mysqli.prepare.php
     */
    $statement = $connection->prepare($sql);
    if (!$statement) {
        throw new Exception('Prepare error: ' . $connection->errno . ' - ' . $connection->error);
    }

    /*
     * Bind variables for the parameter markers (?) in the 
     * SQL statement that was passed to mysqli::prepare. The first 
     * argument of mysqli_stmt::bind_param is a string that contains one 
     * or more characters which specify the types for the corresponding bind variables.
     * 
     * See: http://php.net/manual/en/mysqli-stmt.bind-param.php
     */
    $bound = $statement->bind_param('i', $userId);
    if (!$bound) {
        throw new Exception('Bind error: The variables could not be bound to the prepared statement');
    }

    /*
     * Execute the prepared SQL statement.
     * When executed any parameter markers which exist will 
     * automatically be replaced with the appropriate data.
     * 
     * See: http://php.net/manual/en/mysqli-stmt.execute.php
     */
    $executed = $statement->execute();
    if (!$executed) {
        throw new Exception('Execute error: The prepared statement could not be executed!');
    }

    /*
     * Transfer the result set resulted from executing the prepared statement.
     * E.g. store, e.g. buffer the result set into the (same) prepared statement.
     * 
     * See:
     *      http://php.net/manual/en/mysqli-stmt.store-result.php
     *      https://stackoverflow.com/questions/8321096/call-to-undefined-method-mysqli-stmtget-result
     */
    $resultStored = $statement->store_result();
    if (!$resultStored) {
        throw new Exception('Store result error: The result set  could not be transfered');
    }

    /*
     * Get the number of rows from the prepared statement.
     * 
     * See: http://php.net/manual/en/mysqli-stmt.num-rows.php
     */
    $numberOfRows = $statement->num_rows;

    /*
     * Fetch data and save it into $fetchedData array.
     * 
     * See: http://php.net/manual/en/mysqli-result.fetch-array.php
     */
    if ($numberOfRows > 0) {
        /*
         * Bind the result set columns to corresponding variables.
         * E.g. these variables will hold the column values after fetching.
         * 
         * See: http://php.net/manual/en/mysqli-stmt.bind-result.php
         */
        $varsBound = $statement->bind_result(
                $resOfferName
                , $resTime
                , $resPayout
        );
        if (!$varsBound) {
            throw new Exception('Bind result error: The result set columns could not be bound to variables');
        }

        /*
         * Fetch results from the result set (of the prepared statement) into the bound variables.
         * 
         * See: http://php.net/manual/en/mysqli-stmt.fetch.php
         */
        while ($row = $statement->fetch()) {
            $fetchedObject = new stdClass();

            $fetchedObject->offer_name = $resOfferName;
            $fetchedObject->time = $resTime;
            $fetchedObject->payout = $resPayout;

            $fetchedData[] = $fetchedObject;
        }
    }

    /*
     * Frees the result memory associated with the statement,
     * which was allocated by mysqli_stmt::store_result.
     * 
     * See: http://php.net/manual/en/mysqli-stmt.store-result.php
     */
    $statement->free_result();

    /*
     * Close the prepared statement. It also deallocates the statement handle.
     * If the statement has pending or unread results, it cancels them 
     * so that the next query can be executed.
     * 
     * See: http://php.net/manual/en/mysqli-stmt.close.php
     */
    $statementClosed = $statement->close();
    if (!$statementClosed) {
        throw new Exception('The prepared statement could not be closed!');
    }

    // Close db connection.
    $connectionClosed = $connection->close();
    if (!$connectionClosed) {
        throw new Exception('The db connection could not be closed!');
    }
} catch (mysqli_sql_exception $e) {
    echo 'Error: ' . $e->getCode() . ' - ' . $e->getMessage();
    exit();
} catch (Exception $e) {
    echo $e->getMessage();
    exit();
}

/*
 * Disable internal report functions.
 * 
 * MYSQLI_REPORT_OFF: Turns reporting off.
 * 
 * See:
 *      http://php.net/manual/en/class.mysqli-driver.php
 *      http://php.net/manual/en/mysqli-driver.report-mode.php
 *      http://php.net/manual/en/mysqli.constants.php
 */
$mysqliDriver->report_mode = MYSQLI_REPORT_OFF;
?>

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>Example code: Mysqli prepared statements & exception handling</title>
    </head>
    <style>
        table {
            font-family: "Verdana", Arial, sans-serif;
            font-size: 14px;
            border-collapse: collapse;
        }

        table, th, td {
            border: 1px solid #ccc;
        }

        th, td {
            padding: 7px;
        }

        thead {
            color: #fff;
            font-weight: normal;
            background-color: coral;
        }

        tfoot {
            background-color: wheat;
        }

        tfoot td {
            text-align: right;
        }
    </style>
    <body>

        <?php
        $countOfFetchedData = count($fetchedData);

        if ($countOfFetchedData > 0) {
            ?>
            <table>
                <thead>
                    <tr>
                        <th>Crt. No.</th>
                        <th>OFFER NAME</th>
                        <th>TIME</th>
                        <th>PAYOUT</th>
                    </tr>
                </thead>
                <tbody>
                    <?php
                    foreach ($fetchedData as $key => $item) {
                        $offerName = $item->offer_name;
                        $time = $item->time;
                        $payout = $item->payout;
                        ?>
                        <tr>
                            <td><?php echo $key + 1; ?></td>
                            <td><?php echo $offerName; ?></td>
                            <td><?php echo $time; ?></td>
                            <td><?php echo $payout; ?></td>
                        </tr>
                        <?php
                    }
                    ?>
                </tbody>
                <tfoot>
                    <tr>
                        <td colspan="7">
                            - <?php echo $countOfFetchedData; ?> records found -
                        </td>
                    </tr>
                </tfoot>
            </table>
            <?php
        } else {
            ?>
            <span>
                No records found.
            </span>
            <?php
        }
        ?>

    </body>
</html>

In the end I'd suggest you to use an object-oriented approach, like implementing a MySQLiConnection class (for handling the db connection) and a MySQLiAdapter class (for handling the query functionality). Both classes should be instantiated only once. The MySQLiConnection should be passed as constructor argument to the MySQLiAdapter class. MySQLiAdapter class needs an MySQLiConnection class for querying the db and for receiving the results. You could extend their use by implementing corresponding interfaces too, but I tried to keep my explanation simple.

I'd also suggest you to use PDO instead of MySQLi. One of the reasons I've discovered when I implemented this code: the somewhat challenging exception handling system in MySQLi.

Good luck!

  • @awesomexbox3 You are welcome. Try to always use prepared statements and exception handing. Good luck. –  Jul 14 '17 at 16:04
  • @awesomexbox3 P.S: Your tables need some refactoring. The two should be in a foreign key relation on the id column. –  Jul 14 '17 at 16:08
  • ok but since im using a user management framework should I get rid of define('MYSQL_HOST', '...'); define('MYSQL_PORT', '...'); define('MYSQL_DATABASE', '...'); define('MYSQL_CHARSET', 'utf8'); define('MYSQL_USERNAME', '...'); define('MYSQL_PASSWORD', '...'); and put it in my db file – awesomexbox3 Jul 14 '17 at 16:22
  • and is this the simplest way possible and safe? or is there an easier way because im confused about what cnv. is? – awesomexbox3 Jul 14 '17 at 16:25
  • @awesomexbox3 Yes, these constants should be not defined in the page where the db connection takes place. For example define a function (be it maybe in a Connection class) to connect to db. Then, these connection string variables should be defined as parameters of the function. Like `public function connect($host, $port, $dbName,...)`. And the values for the parameters ("localhost", "3306", "db",...) should be injected as arguments to the function... –  Jul 14 '17 at 16:38
  • @awesomexbox3 ...Where you define these values is your decision. Normally you should save them in a separate configs php file as encoded values ("hjagdfhg4343", "9sft7wikladf", "zztuztuz2t45") - so not readable. But when you pass them to the `connect` function decode them inside it, open the connection with them and delete them with `$host=NULL,...`. –  Jul 14 '17 at 16:40
  • @awesomexbox3 Regarding on what are you referring yourself when you ask "_simplest way possible and safe?_". On db connection, on sql statement, or on the use of prepared statements and exception handling? –  Jul 14 '17 at 16:42
  • @awesomexbox3 "cnv" and "usr" are just aliases for the table names. They are used: 1) To use a shorter name for long table names in (complex) queries. It's better to use an alias "cnv" instead of a table name like "table_conversions_from_users". Which aliases are you defining is your choice. The aliases can be even identical to the table names. 2) To prevent column name conflicts. If you are using `select id, id,... from conversions, users` then the sql engine doesn't know which `id` column belongs to which table. –  Jul 14 '17 at 17:04
  • @awesomexbox3 So you prefix the column names with table names or aliases: `select users.id, conversions.id,... from....`, or `select usr.id, cnv.id,... from conversions AS cnv, users AS usr`. There are also column aliases. When you have `select MAX(LENGTH(usr.id)), cnv.id from conversions AS cnv, users AS usr WHERE MAX(LENGTH(usr.id)) > 2` then is not good. Use column aliases then, like this `select MAX(LENGTH(usr.id)) AS maxy, cnv.id from conversions AS cnv, users AS usr WHERE maxy > 2`. Ok? –  Jul 14 '17 at 17:08