@@ -370,28 +370,69 @@ private function downloadLink($form_id, $title) {
370370 ], '/ ' ) . '.csv ' ;
371371 }
372372
373+ /**
374+ * Create a CSV line with proper escaping for delimiters and newlines
375+ */
376+ private function csvLine (array $ columns ): string
377+ {
378+ $ normalized = array_map (static function ($ value ) {
379+ if ($ value === null ) {
380+ $ value = '' ;
381+ } elseif (is_bool ($ value )) {
382+ $ value = $ value ? '1 ' : '0 ' ;
383+ } elseif (is_array ($ value )) {
384+ $ value = json_encode ($ value , JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES );
385+ } elseif (is_object ($ value )) {
386+ if (method_exists ($ value , 'value ' )) {
387+ $ value = $ value ->value ();
388+ } elseif (method_exists ($ value , '__toString ' )) {
389+ $ value = (string ) $ value ;
390+ } else {
391+ $ value = json_encode ($ value , JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES );
392+ }
393+ }
394+
395+ $ string = (string ) $ value ;
396+
397+ return str_replace (["\r\n" , "\r" ], "\n" , $ string );
398+ }, $ columns );
399+
400+ $ stream = fopen ('php://temp ' , 'r+ ' );
401+ fputcsv ($ stream , $ normalized , '; ' );
402+ rewind ($ stream );
403+ $ line = rtrim (stream_get_contents ($ stream ), "\r\n" );
404+ fclose ($ stream );
405+
406+ return $ line ;
407+ }
408+
373409 public function download ()
374410 {
375411
376412 $ output = null ;
377413
378- function parseField ($ field ) {
414+ $ parseField = static function ($ field ) {
379415 $ array = json_decode ($ field ->value (), true );
380416 unset($ array ['summary ' ]);
381417 return array_values ($ array );
382- }
418+ };
383419
384420 foreach ($ this ->container ->drafts ()->sortBy ('received ' , 'desc ' ) as $ b ) {
385421
386422 $ content = $ b ->content ();
387423 $ received = $ content ->received ()->toValue ();
388424 $ id = $ content ->slug ();
389425
390- $ output ??= A::join (['ID ' , ...parseField ($ content ->formfields ()), 'Received ' ], '; ' ) . "\n" ;
391- $ output .= A::join ([$ id , ...parseField ($ content ->formdata ()), $ received ], '; ' ) . "\n" ;
392-
426+ if ($ output === null ) {
427+ $ header = array_merge (['ID ' ], $ parseField ($ content ->formfields ()), ['Received ' ]);
428+ $ output = $ this ->csvLine ($ header ) . "\n" ;
429+ }
430+
431+ $ row = array_merge ([$ id ], $ parseField ($ content ->formdata ()), [$ received ]);
432+ $ output .= $ this ->csvLine ($ row ) . "\n" ;
433+
393434 }
394-
435+
395436 return $ output ;
396437 }
397438
0 commit comments