首页 > 解决方案 > 如何从 PHP 中的多维数组输出 CSV 文件中缺失属性的空格

问题描述

我在输出空格并确保我所有的 CSV 数据都输出到正确的位置时遇到了一点问题,我想知道我该怎么做。

我正在尝试将我的 LDAP 服务器搜索的输出格式化为 CSV 格式,但问题是某些条目的属性无序,或者某些条目完全缺少属性。

这是一些数据的示例

Array
(
    [0] => Array
        (
            [dc=example,dc=com] => Array
                (
                    [o] => example.com
                    [objectclass] => Array
                        (
                            [0] => simpleSecurityObject
                            [1] => dcObject
                            [2] => organization
                        )

                    [dc] => example
                )

        )

    [1] => Array
        (
            [uid=newton,dc=example,dc=com] => Array
                (
                    [sn] => Newton
                    [objectclass] => Array
                        (
                            [0] => simpleSecurityObject
                            [1] => dcObject
                            [2] => organization
                        )

                    [uid] => Newton
                    [mail] => newton@ldap.forumsys.com
                    [cn] => Isaac Newton
                )

        )

)

请注意,在第一个 ([0]) 数组中,我有一个名为“o”和“dc”的条目,而在第二个中,我没有它们。

所以本质上,我想输出这个:

distinguishedname,o,objectclass,dc,sn,uid,mail,cn
dc=example,dc=com,example.com,{simpleSecurityObject,dcObject,organization},example, , , , 
uid=newton,dc=example,dc=com, ,{simpleSecurityObject,dcObject,organization}, , ,Newton,newton@ldap.forumsys.com,Isaac Newton

我不太确定如何做两件事:

  1. 确保所有缺少的属性都替换为“”,使其显示为空
  2. 确保将正确的属性放在正确的位置。例如,“o”可能是一个条目中的第三个属性,但它可能是另一个条目中的第六个属性。如何确保我的 CSV 数据按以下顺序排列:
distinguishedname,o,objectclass,dc,sn,uid,mail,cn

这是一些以 CSV 格式输出所有数据的代码,但我不确定如何制作空字段并使它们对齐.. 输出只是所有数据的打印。

<?php
$movies = array(
  
    "dc=example,dc=com" => array(
      "o" => "example.com", 
      "objectclass" => array("simpleSecurityObject", "dcObject", "organization"),
      "dc" => "example"),
    
  
    "uid=newton,dc=example,dc=com" => array(
      "sn" => "Newton", 
      "objectclass" => array("simpleSecurityObject", "dcObject", "organization"),
      "uid" => "Newton",
      "mail" => "newton@ldap.forumsys.com",
      "cn" => "Isaac Newton")
    
);

function echo1($n){
  echo "<pre>";
  echo $n;
  echo "</pre>";
}
$i=0;
$hi1 = "";

$attributes_list = array("dn", "objectclass", "cn", "userpassword", "description", "sn", "uid", "mail");

echo "<pre></pre>";
$comma_separated = implode(",", $attributes_list);
echo $comma_separated;


foreach ( $movies as $movie => $val ) {

    //echo "<pre></pre> \n Entry #$i";
    //This prints the name of all the arrays.
    //echo1($movie);
    echo "<pre></pre>";
    echo $movie.",";
    $i = $i + 1;

  //Checks if the value of the key value pair is an array.
  if(is_array($val)){
    //Since it's an array, we access its key value pairs again
    foreach ( $val as $key => $value ) {
      //Check to see if value of key value pair is array
      if(is_array($value)){
        //Prints the name of all the arrays
        echo $key." ";
        //Prints all key value pairs of the array
        $value_array = implode(",", $value);
        print_r($value_array);
        //If $value isn't an array, just prints the key value pairs
      } else{
          /*This is the original code for easier readability
          $hi = "$key : $value";
          echo1($hi);*/
          $hi1 = $hi1.$value.",";
          echo $hi1;
        }
      }
    //If $val isn't an array, prints the key value pairs
  } else{
  foreach ( $val as $key => $value ) {
    $hi = "The key is: $key The value is:$value";
    echo1($hi);
    }
  }

  echo '</dl>';
}
?>

这是输出:

dn,objectclass,cn,userpassword,description,sn,uid,mail
dc=example,dc=com,example.com,objectclass simpleSecurityObject,dcObject,organizationexample.com,example,
uid=newton,dc=example,dc=com,example.com,example,Newton,objectclass simpleSecurityObject,dcObject,organizationexample.com,example,Newton,Newton,example.com,example,Newton,Newton,newton@ldap.forumsys.com,example.com,example,Newton,Newton,newton@ldap.forumsys.com,Isaac Newton,

编辑:

使用 Nigel Ren 的代码,我得到了这个输出。

distinguishedname,o,objectclass,dc,sn,uid,mail,cn
o,{}
objectclass,,{},,,,,,simpleSecurityObject,dcObject,organization
dc,{}
sn,{}
objectclass,,{},,,,,,simpleSecurityObject,dcObject,organization
uid,{}
mail,{}
cn,{}

这是我尝试过的确切代码:

<?php

// Start with the column list and split into an array
$headers = explode(',', 'distinguishedname,o,objectclass,dc,sn,uid,mail,cn');
// Create template record with the fields you want to end up with
$header = array_fill_keys($headers, null);
$output = [];

$details = array(
  
    "dc=example,dc=com" => array(
      "o" => "example.com", 
      "objectclass" => array("simpleSecurityObject", "dcObject", "organization"),
      "dc" => "example"),
    
  
    "uid=newton,dc=example,dc=com" => array(
      "sn" => "Newton", 
      "objectclass" => array("simpleSecurityObject", "dcObject", "organization"),
      "uid" => "Newton",
      "mail" => "newton@ldap.forumsys.com",
      "cn" => "Isaac Newton")
    
);

foreach ( $details as $detail ) {
    foreach ( $detail as $name => $entry )  {
        // Set the values in the template header from the current entry
        $newEntry = array_merge( $header, $entry );
        // Add the name in
        $newEntry ['distinguishedname'] = $name;
        // Process the object class from an array to a string
        $newEntry ['objectclass'] = "{".implode(",", $newEntry ['objectclass'])."}";
        $output [] = $newEntry;
    }
}

// Write file out
$fh = fopen("ad.csv", "w");
fputcsv($fh, $headers);
foreach ( $output as $row ) {
    fputcsv($fh, $row);
}
fclose($fh);

?>

编辑 2020 年 7 月 1 日:

这是我得到的输出

firstname,lastname,email,phone,uid
,,,,,"{top,dcObject,organization}",ec_testing,test123,"{organizationalPerson,person,top,user}"
,,,,,"{simpleSecurityObject,organizationalRole}",admin,"LDAP administrator",{SSHA}0NhB8bVqiqCfUjU7AGE2mtrfj3Q58mj5
,,,,,organizationalUnit,people
,,,,,organizationalUnit,"groups "
,,,,tnguyen,"{top,account,posixAccount,shadowAccount}",tnguyen,16859,100,/home/tnguyen,/bin/bash,tnguyen,{crypt}x,0,0,0
,,,,,"{top,organizationalRole,simpleSecurityObject}","{replica,test}",aDifferentSecret,"Bind object used for replication using slurpd"
,,,,,"{php testing,phptest}",person,TestEdit
,,,,,person,"This is just a test to add an entry in Java",javatest,replacetest
,,,,,gotest,person,Google,"this is to test if replacing works in GoLang"

这是我使用的代码:

foreach ( $details as $name => $entry )  {
    // Set the values in the template header from the current entry
  
    $newEntry = array_merge( $header, $entry );
    // Add the name in
    foreach ( $newEntry as &$entry )    {
        if ( is_array($entry))  {
            $entry = "{".implode(",", $entry)."}";
        }
    }
    unset($entry);
    //$newEntry ['distinguishedname'] = $name;
    $output [] = $newEntry;
}

我希望输出像

firstname,lastname,email,phone,uid
,,,,
,,,,
,,,,
,,,,
,,,,tnguyen
,,,,
,,,,
,,,,
,,,,

这是一个不好的例子,因为如果不是所有属性,所有条目都缺少大部分,但你明白了。

我试过的是这样的:

foreach ( $details as $name => $entry )  {
    // Set the values in the template header from the current entry
    if(in_array($entry, $header) || in_array($name, $header)){
      $newEntry = array_merge( $header, $entry );
    }
    // Add the name in
    foreach ( $newEntry as &$entry )    {
        if ( is_array($entry) && in_array($newEntry, $header))  {
            $entry = "{".implode(",", $entry)."}";
        }
    }
    unset($entry);
    //$newEntry ['distinguishedname'] = $name;
    $output [] = $newEntry;
}

但它只是输出我的标题,而不仅仅是空条目。

firstname,lastname,email,phone,uid

标签: phpcsvldap

解决方案


以下代码创建一个模板数组,以便每条记录包含所有值,然后用于将每条记录中的值array_merge()复制到模板中。任何不在记录中的值都将保持为空,以确保保持对齐(代码注释中的更多描述)......

// Start with the column list and split into an array
$headers = explode(',', 'distinguishedname,o,objectclass,dc,sn,uid,mail,cn');
// Create template record with the fields you want to end up with
$header = array_fill_keys($headers, null);
$output = [];
foreach ( $details as $detail ) {
    foreach ( $detail as $name => $entry )  {
        // Set the values in the template header from the current entry
        $newEntry = array_merge( $header, $entry );
        // Add the name in
        $newEntry ['distinguishedname'] = $name;
        // Process the object class from an array to a string
        $newEntry ['objectclass'] = "{".implode(",", $newEntry ['objectclass'])."}";
        $output [] = $newEntry;
    }
}

// Write file out
$fh = fopen("ad.csv", "w");
fputcsv($fh, $headers);
foreach ( $output as $row ) {
    fputcsv($fh, $row);
}
fclose($fh);

这与样本数据给出了......

distinguishedname,o,objectclass,dc,sn,uid,mail,cn
"dc=example,dc=com",example.com,"{simpleSecurityObject,dcObject,organization}",example,,,,
"uid=newton,dc=example,dc=com",,"{simpleSecurityObject,dcObject,organization}",,Newton,Newton,newton@ldap.forumsys.com,"Isaac Newton"

请注意, usingfpustcsv()的优点是如果字段包含逗号(分隔符),那么它将把它们放在引号中以确保它们只是一个字段。

编辑:

$headers = explode(',', 'distinguishedname,o,objectclass,dc,sn,uid,mail,cn');
$output = [];
foreach ( $details as $name => $entry )  {
    echo $name.PHP_EOL;
    $newEntry = [];
    foreach ( $headers as $header ) {
        $value = $entry[$header] ?? null;
        if ( is_array($value) ) {
            $value = "{".implode(",", $value)."}";
        }
        $newEntry [$header] = $value;
    }
    $newEntry ['distinguishedname'] = $name;
    $output [] = $newEntry;
}

推荐阅读