1

I have created a web application to allow users to upload CSV files into SQL Server. I have 8 columns in total. The id column in SQL Server is auto-increment so minus that column. The upload was successful however data imported are all null in each column. Also the number of records in my CSV is less than 100 however my SQL Server is showing more than 100 records imported which doesn't tally. Can anyone help to check what is wrong with my code?

Below is my code and a screenshot of my CSV file and SQL Server table.

<?php

$self = $_SERVER['PHP_SELF'];
$request = $_SERVER['REQUEST_METHOD'];

if (!isset($_GET['success'])) {
$get_success = "";
}
else {
$get_success = $_GET['success'];
}

if (!empty($_FILES)) { 

    /* Format the errors and die */
    
    function get_last_error() {
        $retErrors = sqlsrv_errors(SQLSRV_ERR_ALL);
        $errorMessage = 'No errors found';

        if ($retErrors != null) {
            $errorMessage = '';

            foreach ($retErrors as $arrError) {
                $errorMessage .= "SQLState: ".$arrError['SQLSTATE']."<br>\n";
                $errorMessage .= "Error Code: ".$arrError['code']."<br>\n";
                $errorMessage .= "Message: ".$arrError['message']."<br>\n";
            }
        }

        die ($errorMessage);
    }

    /* connect */
    function connect() {
        if (!function_exists('sqlsrv_num_rows')) { // Insure sqlsrv_1.1 is loaded.
            die ('sqlsrv_1.1 is not available');
        }

        /* Log all Errors */
        sqlsrv_configure("WarningsReturnAsErrors", TRUE);        // BE SURE TO NOT ERROR ON A WARNING
        sqlsrv_configure("LogSubsystems", SQLSRV_LOG_SYSTEM_ALL);
        sqlsrv_configure("LogSeverity", SQLSRV_LOG_SEVERITY_ALL);

        $conn = sqlsrv_connect('servername', array
        (
        'UID' => '',
        'PWD' => '',
        'Database' => 'databasename',
        'CharacterSet' => 'UTF-8',
        'MultipleActiveResultSets' => true,
        'ConnectionPooling' => true,
        'ReturnDatesAsStrings' => true,
        ));

        if ($conn === FALSE) {
            get_last_error();
        }

        return $conn;
    }

    function query($conn, $query) {
        $result = sqlsrv_query($conn, $query);
        if ($result === FALSE) {
            get_last_error();
        }
        return $result;
    }

    /* Prepare a reusable query (prepare/execute) */
    
    function prepare ( $conn, $query, $params ) {
        $result = sqlsrv_prepare($conn, $query, $params);
        if ($result === FALSE) {
            get_last_error();
        }
        return $result;
    }

    /*
    do the deed. once prepared, execute can be called multiple times
    getting different values from the variable references.
    */
    
    function execute ( $stmt ) {
        $result = sqlsrv_execute($stmt);
        if ($result === FALSE) {
            get_last_error();
        }
        return $result;
    }

    function fetch_array($query) {
        $result = sqlsrv_fetch_array($query, SQLSRV_FETCH_ASSOC);
        if ($result === FALSE) {
            get_last_error();
        }
        return $result;
    }

    $conn = connect();

    /* prepare the statement */
    $query = "INSERT TABLEName values ( ? , ? , ? , ?, ?, ?, ?, ?)";
    $param1 = null; // this will hold col1 from the CSV
    $param2 = null; // this will hold col2 from the CSV
    $param3 = null; // this will hold col3 from the CSV
    $param4 = null; // this will hold col4 from the CSV
    $param5 = null; // this will hold col5 from the CSV
    $param6 = null; // this will hold col6 from the CSV
    $param7 = null; // this will hold col7 from the CSV
    $param8 = null; // this will hold col8 from the CSV
    $params = array( $param1, $param2, $param3, $param4, $param5, $param6, $param7, $param8 );
    $prep = prepare ( $conn, $query, $params );
    //$result = execute ( $prep );

    //get the csv file 
    
    $file = $_FILES["csv"]["tmp_name"]; 
    
  /*
    Here is where you read in and parse your CSV file into an array.
    That may get too large, so you would have to read smaller chunks of rows.
  */
  
    $csv_array = file($file);
    foreach ($csv_array as $row_num => $row) {
        $row = trim ($row);
        $column = explode ( ',' , $row );
        $param1 = $column[0];
        $param2 = $column[1];
        $param3 = $column[2];
        $param4 = $column[3];
        $param5 = $column[4];
        $param6 = $column[5];
        $param7 = $column[6];
        $param8 = $column[7];
        // insert the row
        
        $result = execute ( $prep );
    }
    
/* Free statement and connection resources. */

sqlsrv_close($conn);
header( "Location: uploadcsv.php?success=1" );
}

?>


<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <meta name="description" content="">
    <meta name="author" content="">
    <title>CSV Upload</title>
</head>
<body>
<?php if (!empty($get_success)) { echo "<b>Your file has been imported.</b><br><br>"; } //generic success notice ?> 

<form action="" method="post" enctype="multipart/form-data" name="uploadcsv" id="uploadcsv"> 
  Upload a CSV file from your computer: <br /> 
  <input name="csv" type="file" id="csv" /> 
  <input type="submit" name="Submit" value="Submit" /> 
</form> 


<body>
</html>

CSV data file

CSV

sqlserver table

enter image description here

0

1 Answer 1

1

There are two major problems with the code posted:

  1. CSV data is not being read in correctly, and
  2. The $params array supplied to prepare() isn't being updated correctly.

Problem 1: Reading in CSV.

You're using PHP's file() method to read CSV files.

If you're trying to parse CSV files line-by-line and then split lines on commas you're doing it wrong. Have a read through RFC 4180 Common Format and MIME Type for Comma-Separated Values (CSV) Files to see how CSV files are structured and notice that field datas can contain commas, quotes and line break characters. i.e.: You need a character-oriented state machine to parse them.

The correct way to do it is to use a CSV parsing function or library that somebody else has already written and debugged for you, e.g.: fgestcsv().

Consider the following example...

foo1.csv:

col1,col2,col3
alpha,bravo,charlie
"hello,
""cruel""
world!",bravo,charlie

foo1.php:

<?php
if (($handle = fopen("foo1.csv", "r")) !== FALSE) {
    $row = 1;
    while (($data = fgetcsv($handle, 1000, ",")) !== FALSE) {
        print "Row $row: ";
        var_dump($data);
        $row++;
    }
    fclose($handle);
}
?>

When run this outputs...

% php -f foo1.php
Row 1: array(3) {
  [0]=>
  string(4) "col1"
  [1]=>
  string(4) "col2"
  [2]=>
  string(4) "col3"
}
Row 2: array(3) {
  [0]=>
  string(5) "alpha"
  [1]=>
  string(5) "bravo"
  [2]=>
  string(7) "charlie"
}
Row 3: array(3) {
  [0]=>
  string(19) "hello,
"cruel"
world!"
  [1]=>
  string(5) "bravo"
  [2]=>
  string(7) "charlie"
}

Problem 2: Updating $params correctly

The code posted constructs an array from variables and then updates the variables with CSV data. This won't work, consider the following...

foo2.php:

<?php
$param1 = null;
print "\$param1 = ";
var_dump($param1);

$params = array($param1);
print "\$params = ";
var_dump($params);

$param1 = 42;
print "\$param1 = ";
var_dump($param1);
print "\$params = ";
var_dump($params);

$params[0] = 47;
print "\$params = ";
var_dump($params);
?>

When run this outputs...

% php -f foo2.php
$param1 = NULL
$params = array(1) {
  [0]=>
  NULL
}
$param1 = int(42)
$params = array(1) {
  [0]=>
  NULL
}
$params = array(1) {
  [0]=>
  int(47)
}

Notice how $param1 was updated to 42 successfully but $params[0] was still NULL? $params was only updated when we set a applied via $params[0] directly.

Your CSV reading code (hopefully updated to use fgestcsv()) should be updating the $params[0] through $params[7] array elements directly.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.