Transformer un tableau d'objets en tableau unidimensionnel

Description

Pour les besoins d'un webmail que je remets à jour j'avais besoin de traiter les tableaux d'objets renvoyés par la fonction imap_fetchstructure. Il existe quelques exemples sur le site de PHP (www.php.net) mais rien en procéduriel, que de l'objet et moi, l'objet, ça me file des boutons! J'ai donc décidé de développé ma propre fonction.

Le principe est de traiter le tableau d'objet par niveau. Le faire de manière naturelle, comme un humain lierait le tableau aurait été beaucoup trop dur pour moi.
Afin de s'y retrouver ma fonction renomme chaque clef en récupérant le nom d'objet de la valeur traitée.

Source / Exemple :


<?php

//$a est un tableau d'objets renvoyé par la fonction imap_fetch_structure

//On liste dans un tableau tous les objets renvoyés par la fonction
$valeurs_objet = array ("type", "encoding", "ifsubtype", "subtype", "ifdescription", "descritpion", "ifid", "id", "lines", "bytes", "ifdisposition", "disposition", "ifdparameters", "dparameters", "ifparameters", "parameters", "parts");

print_r ($a);
echo "<br><br><br>";

//On stocke les chemins amenant à un sous tableau
$stock_tableau = array();

//Tableau de sortie que l'on pourra travailler après
$recup_donnees = array();

//Variable incrémentable pour le premier niveau qui servira a appelé les noms d'objets contenus dans $valeur_objet
$numero = 0;

//On fait tourner la boucle tant que le tableau d'objets $a n'a pas entièrement été lu
while (!$arret_boucle) {

	//On traite le 1er niveau
	if (empty ($stock_tableau) || empty ($niveau)) {

		if ($numero<17) {
			//On récupère la valeur courante de $a
			$valeur_courante = $a -> $valeurs_objet[$numero];

			//Si la valeur courante est un tableau on stocke le chemin dans $stock_tableau
			if (is_array ($valeur_courante)) {
				array_push ($stock_tableau, $valeurs_objet[$numero]);
			} else {
				//Si la valeur courante est une simple valeur on la stocke avec le nom d'objet en clef dans le tableau $recup_donnees
				if (isset ($valeur_courante)) {
					$recup_donnees[$valeurs_objet[$numero]] = $valeur_courante;
				}
			}
			$numero++;
		//Si le premier niveau est terminé on met un séparateur et l'on passe au 2ème niveau
		} else {
			array_push ($stock_tableau, "/,,/");
			array_push ($recup_donnees, "/,,/");
			$niveau = 1;
		}

	//On traite les niveaux supérieurs
	} else {
		$valeur_courante2 = current ($stock_tableau);
		next ($stock_tableau);
		
		//Niveau 3 et supérieur
		if (is_array ($valeur_courante2)) {
			//On compte le nombre de valeurs contenues dans le tableau
			$compte_tableau3 = count ($valeur_courante2);

			//On copie le tableau pour le triturer afin de ne pas abîmer le tableau original
			$resultat2 = $a -> parts;

			//On épluche le tableau $resultat2 pour obtenir le morceau désiré
			for ($d=0;$d<$compte_tableau3;$d++) {
				//La distinction est obligatoire car le compilateur ne reconnaît pas les appels du genre $truc->$a->$b. Il faut préciser $a et $b si ce sont des objets
				if ($d%2 == 0) {
					//Le +0 est très important sinon le résultat obtenu sera tout autre. On teste la valeur courante appelée afin de déterminer s'il s'agit d'un objet ou d'un tableau
					$resultat2 = $resultat2[$valeur_courante2[$d]+0];
				} else {
					//On définit le saut suivant
					if ($valeur_courante2[$d] == "parameters") {
						$resultat2 = $resultat2->parameters;
					} else if ($valeur_courante2[$d] == "dparameters") {
						$resultat2 = $resultat2->dparameters;
					} else if ($valeur_courante2[$d] == "parts") {
						$resultat2 = $resultat2->parts;
					}
				}
			}

			//On compte le nombre de valeurs contenues dans le tableau épluché
			$compte_resultat2 = count ($resultat2);
			
			//On compte le nombre de valeurs du tableau contenu dans la variable $valeur_courante2
			$compte_valeur_courante2 = count ($valeur_courante2);

			//On analyse la valeur courante du tableau $resultat2
			for ($e=0;$e<$compte_resultat2;$e++) {

				//permet d'incrémenter les différentes clefs attribute et value
				$g = $c++;

				//On regarde si la valeur courante est parameters ou dparameters afin de récupérer les valeurs de attribute et value avec les noms d'objets en clef indexés
				if (strcmp ($valeur_courante2[$compte_valeur_courante2-1], "parameters") == 0 || strcmp ($valeur_courante2[$compte_valeur_courante2-1], "dparameters") == 0) {
					$recup_donnees[attribute.$g] = $resultat2[$e] -> attribute;
					$recup_donnees[value.$g] = $resultat2[$e] -> value;
				
				//idem pour parts. Dans ce cas on teste toutes les valeurs derrière parts afin de déterminer s'il y a un tableau d'objet ou une simple valeur
				} else if (strcmp ($valeur_courante2[$compte_valeur_courante2-1], "parts") == 0) {
					for ($i=0;$i<17;$i++) {
						//On vérifie que l'objet existe
						if (isset ($resultat2[$e] -> $valeurs_objet[$i])) {
							//Si la valeur retournée est un tableau on réupère le chemin, on ajoute la dernière clef, on injecte le tout dans un tableau que l'on met dans $stock_tableau
							if (is_array ($resultat2[$e] -> $valeurs_objet[$i])) {
								$boom = implode (",", $valeur_courante2);
								$boom2 = "$boom, $e,$valeurs_objet[$i]";
								$colle = explode (",", $boom2);
								array_push ($stock_tableau, $colle);
							//Si la clef contient une simple valeur on la stocke dans $recup_donnees
							} else {
								$recup_donnees[$valeurs_objet[$i].$g] = $resultat2[$e] -> $valeurs_objet[$i];
							}
						}
					}
				}
			}

		//Une fois le niveau courant terminé (2ème ou supérieur) on met une séparation et l'on passe au niveau suivant
		} else if (empty ($valeur_courante2) || $valeur_courante2 == "/,,/") {
			$verif = count ($stock_tableau)-1;
			
			if ($stock_tableau[$verif] != "/,,/") {
				array_push ($stock_tableau, "/,,/");
				array_push ($recup_donnees, "/,,/");
			
			//Si tout le tableau d'objet a été lu on arrête la boucle
			} else {
				$arret_boucle = 1;
			}

		//Niveau 2
		} else {
			//On récupère la valeur courante
			$resultat = $a -> $valeur_courante2;
			
			//On compte le nombre d'éléments contenu dans le tableau
			$compte_tableau2 = count ($resultat);

			//On teste toutes les clefs du tableau afin de savoir si la valeur est un tableau, un objet ou une simple valeur
			for ($c=0;$c<$compte_tableau2;$c++) {
				//Si la valeur courante est parameters on stocke son contenu dans $recup_donnees et on met le nom des objets en clefs suivi d'un indice numérique pour ne pas que le compilateur considère
				//qu'il n'y ait qu'une seule clef et donc qu'une seule valeur
				if ($valeur_courante2 == "parameters") {
					$recup_donnees[attribute.$c] = $resultat[$c] -> attribute;
					$recup_donnees[value.$c] = $resultat[$c] -> value;
				//idem si la valeur courante est dparameters
				} else if ($valeur_courante2 == "dparameters") {
					$recup_donnees[attribute.$c+1] = $resultat[$c] -> attribute;
					$recup_donnees[value.$c+1] = $resultat[$c] -> value;
				//Si la valeur courante est parts on recommence à tester toutes les valeurs contenues après parts pour savoir si les clefs contiennent des objets ou de simples valeurs
				} else if ($valeur_courante2 == "parts") {
					for ($f=0;$f<17;$f++) {
						//On vérifie que l'objet courant appelé existe
						if (isset ($resultat[$c] -> $valeurs_objet[$f])) {
							//Si l'objet courant appelé est un tableau on stocke le chemin dans $stock_tableau, sinon on inscrit la valeur dans $recup_donnees
							if (is_array ($resultat[$c] -> $valeurs_objet[$f])) {
								array_push ($stock_tableau, array ($c, $valeurs_objet[$f]));
							} else {
								$recup_donnees[$valeurs_objet[$f].$c] = $resultat[$c] -> $valeurs_objet[$f];
							}
						}
					}
				}
			} 
		}
	}
}

echo "<br><br><br>";
echo "recup_donnees : ";
print_r ($recup_donnees);

}

?>

Conclusion :


J'espère que cette fonction pourra aider ceux qui veulent utiliser la fonction imap_fetchstructure qui peut renvoyer un tableau d'objet très vite énorme selon le mail analisé (un forward de forward avec pièces jointes, fichiers incorporés, etc...)

Codes Sources

A voir également

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.