Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

Tektōn's avatar

How to read csv data, loop through the array to make some modifications before save it into the database

First of all, I'd to thank you in advance for each of you who are helping me with this, and I am sorry for this huge post. I want to provide as many details as I could.

I'd like to know how to read CSV, convert the data into array, loop through the array to create or update, push status to each row as "New" (if doesn't exist and create) or "Updated" (if exist and edited), save to database, and output array into a table. I am using the Maatwebsite\Excel package.

The CSV was exported by the users from another website, not sure why but there are two headings with the name Price but with different specific purposes. Here is the sample CSV:

Date Added,Address,Land Size,Price,Price,Location ID
10-Nov-21,123 Gargamel Road,789,”6,680,000”,"5000.12",15
11-Nov-21,45 Gorillaz Road,123,”5,500,000”,"2500.34",13

After the file is read, the Address column will be split into house_number and street_name. Example: 123 Gargamel Road to become house_number='123' and street_name='Gargamel Road'.

There are 2 columns with the same header name as "Price" as I mentioned above. The first Price column value should be 6680000 because the data type in the database is Integer, and the second Price column value should be 5000.12 because the data type in the database is Decimals.

• Check if there are similar data in the database based on house_number and street_name. This will allow Admin to check if they already have previously inputted data to the database but with a slightly different name or typo. For example “168 Gargamel Road” with “168 Gargamel Rd” or “168 Gargml Road”. If not, set the data status as "New".

• If there are similar data, display both data sets from the CSV and database for comparison for Admin to review. Admin then can decide whether to import each row as new data or edit the existing data.

Here is the route file:

Route::get('import', 'ImportController@import')->name('import');
Route::post('import_parse', 'ImportController@parseImport')->name('import_parse');
Route::post('import_process', 'ImportController@processImport')->name('import_process');

Here is the ImportController I previously have. It is used to read if the CSV has headings and data, then save data to a csv_data table as JSON. But, this is no longer an option because the users don't want to create a new table. They just want to directly display CSV data after read, and do processing for editing before import.

public function parseImport ( CsvImportRequest $request )
{

        if ( $request->has( 'header' ) )
        {
            $headings = ( new HeadingRowImport )->toArray( $request->file( 'csv_file' ) );
            $data = Excel::toArray( new DataImport(), $request->file( 'csv_file' ) )[0];
        } else
        {
            $data = array_map( 'str_getcsv', file( $request->file( 'csv_file' )->getRealPath() ) );
        }

        if ( count( $data ) > 0 )
        {
           $csv_data_file = CsvData::create( [
                'csv_filename' => $request->file( 'csv_file' )->getClientOriginalName(),
                'csv_header'   => $request->has( 'header' ),
                'csv_data'     => json_encode( $data )
            ] );
        } else
        {
            return redirect()->back();
        }
}

public function processImport ( Request $request )
    {
        $data = CsvData::find( $request->csv_data_file_id );
        $csv_data = json_decode( $data->csv_data, true );
        foreach ( $csv_data as $row )
        {
            $listing = new Listing();
            foreach ( config( 'app.db_fields' ) as $index => $field )
            {
                if ( $data->csv_header )
                {
                    $listing->$field = $row[$request->fields[$field]];
                } else
                {
                    $listing->$field = $row[$request->fields[$index]];
                }
            }
            $contact->save();
        }
return redirect( 'import' )->with( 'status', 'Excel file imported successfully.' );

}

Here is the CsvImportRequest:

class CsvImportRequest extends FormRequest
{
    public function rules(): array
    {
        return [
            'csv_file' => ['required', 'file', 'mimes:csv,txt,xls,xlsx']
        ];
    }

    public function authorize(): bool
    {
        return true;
    }
}

Here is my DataImport. The data start from csv row 3.

class DataImport implements WithStartRow, WithHeadingRow
{
    public function startRow(): int
    {
        return 3;
    }
}

Here is the blade file. This will show the data and process the import when submit button is clicked. But I am still unsure how to edit each row if the data is only read from CSV and not from the database:

<form method="POST" action="{{ route('import_process') }}">
    @csrf

     <table class="table table-striped">
         <th>Date Added</th>
         <th>Address</th>
         <th>Land Size</th>
         <th>Price</th>
         <th>Price</th>
         <th>Location ID</th>
         <th>Action</th>

         <body>

          @foreach($csv_data as $row)
               <tr>
                  @foreach ($row as $key => $value)
                      <td>
                          {{ $value }}
                      </td>
                  @endforeach
                </tr>
                <tr>
                    <a href="" type=button" class="btn btn-info">
                       Edit
                    </a>
                </tr>
                <tr>
                    <a href="" type=button" class="btn btn-danger">
                       Delete
                    </a>
                </tr>
            @endforeach
        
         </tbody>

     </table>

    <button type="submit" class="btn btn-primary">
        Submit Data to Import
    </button>
</form>
0 likes
1 reply
jlrdw's avatar

I wrote one a while back that pulls in checking data for a non profit, only certain fields were needed. Also not in laravel, but you should get the gerenal idea, just convert the "PHP" portions to laravel coding:

    public function incsv()
    {
        $file = 'C:\mydocs\incsv.csv';
        $content = file($file);
        $array = array();

        for ($i = 1; $i < count($content); $i++) {
            $line = explode(',', $content[$i]);
            for ($j = 0; $j < count($line); $j++) {
                $array[$i][$j + 1] = $line[$j];
            }
        }

        $k = count($array) + 1;

        for ($i = 1; $i < $k; $i++) {
            $tdate = new \DateTime($array[$i][2]);
            $ndate = $tdate->format('Y-m-d');
            $descraw = $array[$i][8];
            $descspace = preg_replace('/[^a-z\d ]/i', '', $descraw);
            $desc = preg_replace('/^\s+|\s+$|\s+(?=\s)/', '', $descspace);
            $amt = (float) $array[$i][3];
            $namt = number_format($amt, 2, '.', '');
            if ($namt < 0) {
                $wd = $namt * -1;
                $dep = 0;
            } else {
                $wd = 0;
                $dep = $namt;
            }

            $maxid = $this->Check->getMaxid();
            $checkid = $maxid + 1;

            $data = [
                'checkid' => $checkid,
                'transdate' => $ndate,
                'transdescribe' => $desc,
                'widthdraw' => $wd,
                'deposit' => $dep
            ];
            $this->Check->insertCsv($data);
        }

        $this->Check->checkRecalc();
        Url::redirect('check/index');
    }

You probably don't need preg_replace lines they remove stray unwanted characters not needed and stray blank spaces.

Example:

2 likes

Please or to participate in this conversation.