J'aimerais créer une page où toutes les images qui résident sur mon site Web sont répertoriées avec un titre et une représentation alternative.
J'ai déjà écrit un petit programme pour trouver et charger tous les fichiers HTML, mais je ne sais plus comment extraire src
, title
et alt
de ce code HTML:
<img src="/image/fluffybunny.jpg" title="Harvey the bunny" alt="a cute little fluffy bunny" />
Je suppose que cela devrait être fait avec une regex, mais comme l’ordre des tags peut varier et que j’ai besoin de tous, je ne sais pas vraiment comment analyser cela de manière élégante (je pourrais le faire avec hard char par char façon, mais c'est douloureux).
Utiliser regexp pour résoudre ce genre de problème est ne mauvaise idée et mènera probablement à un code non maintenable et peu fiable. Mieux vaut utiliser un analyseur HTML .
Dans ce cas, il est préférable de scinder le processus en deux parties:
Je supposerai que votre document n'est pas xHTML strict, vous ne pouvez donc pas utiliser un analyseur XML. PAR EXEMPLE. avec le code source de cette page Web:
/* preg_match_all match the regexp in all the $html string and output everything as
an array in $result. "i" option is used to make it case insensitive */
preg_match_all('/<img[^>]+>/i',$html, $result);
print_r($result);
Array
(
[0] => Array
(
[0] => <img src="/Content/Img/stackoverflow-logo-250.png" width="250" height="70" alt="logo link to homepage" />
[1] => <img class="vote-up" src="/content/img/vote-arrow-up.png" alt="vote up" title="This was helpful (click again to undo)" />
[2] => <img class="vote-down" src="/content/img/vote-arrow-down.png" alt="vote down" title="This was not helpful (click again to undo)" />
[3] => <img src="http://www.gravatar.com/avatar/df299babc56f0a79678e567e87a09c31?s=32&d=identicon&r=PG" height=32 width=32 alt="gravatar image" />
[4] => <img class="vote-up" src="/content/img/vote-arrow-up.png" alt="vote up" title="This was helpful (click again to undo)" />
[...]
)
)
Ensuite, nous obtenons tous les attributs de la balise img avec une boucle:
$img = array();
foreach( $result as $img_tag)
{
preg_match_all('/(alt|title|src)=("[^"]*")/i',$img_tag, $img[$img_tag]);
}
print_r($img);
Array
(
[<img src="/Content/Img/stackoverflow-logo-250.png" width="250" height="70" alt="logo link to homepage" />] => Array
(
[0] => Array
(
[0] => src="/Content/Img/stackoverflow-logo-250.png"
[1] => alt="logo link to homepage"
)
[1] => Array
(
[0] => src
[1] => alt
)
[2] => Array
(
[0] => "/Content/Img/stackoverflow-logo-250.png"
[1] => "logo link to homepage"
)
)
[<img class="vote-up" src="/content/img/vote-arrow-up.png" alt="vote up" title="This was helpful (click again to undo)" />] => Array
(
[0] => Array
(
[0] => src="/content/img/vote-arrow-up.png"
[1] => alt="vote up"
[2] => title="This was helpful (click again to undo)"
)
[1] => Array
(
[0] => src
[1] => alt
[2] => title
)
[2] => Array
(
[0] => "/content/img/vote-arrow-up.png"
[1] => "vote up"
[2] => "This was helpful (click again to undo)"
)
)
[<img class="vote-down" src="/content/img/vote-arrow-down.png" alt="vote down" title="This was not helpful (click again to undo)" />] => Array
(
[0] => Array
(
[0] => src="/content/img/vote-arrow-down.png"
[1] => alt="vote down"
[2] => title="This was not helpful (click again to undo)"
)
[1] => Array
(
[0] => src
[1] => alt
[2] => title
)
[2] => Array
(
[0] => "/content/img/vote-arrow-down.png"
[1] => "vote down"
[2] => "This was not helpful (click again to undo)"
)
)
[<img src="http://www.gravatar.com/avatar/df299babc56f0a79678e567e87a09c31?s=32&d=identicon&r=PG" height=32 width=32 alt="gravatar image" />] => Array
(
[0] => Array
(
[0] => src="http://www.gravatar.com/avatar/df299babc56f0a79678e567e87a09c31?s=32&d=identicon&r=PG"
[1] => alt="gravatar image"
)
[1] => Array
(
[0] => src
[1] => alt
)
[2] => Array
(
[0] => "http://www.gravatar.com/avatar/df299babc56f0a79678e567e87a09c31?s=32&d=identicon&r=PG"
[1] => "gravatar image"
)
)
[..]
)
)
Les expressions régulières nécessitent beaucoup de temps de traitement, vous voudrez peut-être mettre cette page en cache. Si vous n'avez pas de système de cache, vous pouvez modifier votre propre en utilisant ob_start et en chargeant/sauvegardant depuis un fichier texte.
Premièrement, nous utilisons preg_ match_all , une fonction qui récupère chaque chaîne correspondant au modèle et le renvoie dans son troisième paramètre.
Les expressions régulières:
<img[^>]+>
Nous l'appliquons sur toutes les pages Web html. Il peut être lu comme chaque chaîne qui commence par "<img
", contient un caractère non ">" et se termine par un> .
(alt|title|src)=("[^"]*")
Nous l'appliquons successivement sur chaque tag img. Il peut être lu comme chaque chaîne commençant par "alt", "title" ou "src", puis un "=", puis un "", un tas de choses qui ne sont pas " "'et se termine par un" ". Isolez les sous-chaînes entre () .
Enfin, chaque fois que vous voulez gérer les expressions rationnelles, il est utile d’avoir de bons outils pour les tester rapidement. Vérifiez ceci testeur d'expressions rationnelles en ligne .
EDIT: répondez au premier commentaire.
Il est vrai que je n’ai pas pensé aux personnes (espérons-le rares) utilisant des guillemets simples.
Eh bien, si vous utilisez seulement ', remplacez simplement tous les "par".
Si vous mélangez les deux. D'abord, vous devriez vous gifler :-), puis essayez d'utiliser ("| ') à la place ou" et [^ ø] pour remplacer [^ "].
$url="http://example.com";
$html = file_get_contents($url);
$doc = new DOMDocument();
@$doc->loadHTML($html);
$tags = $doc->getElementsByTagName('img');
foreach ($tags as $tag) {
echo $tag->getAttribute('src');
}
Juste pour donner un petit exemple d'utilisation de la fonctionnalité XML de PHP pour cette tâche:
$doc=new DOMDocument();
$doc->loadHTML("<html><body>Test<br><img src=\"myimage.jpg\" title=\"title\" alt=\"alt\"></body></html>");
$xml=simplexml_import_dom($doc); // just to make xpath more simple
$images=$xml->xpath('//img');
foreach ($images as $img) {
echo $img['src'] . ' ' . $img['alt'] . ' ' . $img['title'];
}
J'ai utilisé la méthode DOMDocument::loadHTML()
car cette méthode peut gérer la syntaxe HTML et ne force pas le document d'entrée à être XHTML. Strictement parlant, la conversion en SimpleXMLElement
n'est pas nécessaire - elle simplifie l'utilisation de xpath et des résultats de xpath.
Si vous utilisez l'exemple XHTML, vous n'avez besoin que de XML simple.
<?php
$input = '<img src="/image/fluffybunny.jpg" title="Harvey the bunny" alt="a cute little fluffy bunny"/>';
$sx = simplexml_load_string($input);
var_dump($sx);
?>
Sortie:
object(SimpleXMLElement)#1 (1) {
["@attributes"]=>
array(3) {
["src"]=>
string(22) "/image/fluffybunny.jpg"
["title"]=>
string(16) "Harvey the bunny"
["alt"]=>
string(26) "a cute little fluffy bunny"
}
}
Le script doit être édité comme ceci
foreach( $result[0] as $img_tag)
parce que preg_match_all retourne un tableau de tableaux
Vous pouvez utiliser simplehtmldom . La plupart des sélecteurs jQuery sont pris en charge dans simplehtmldom. Un exemple est donné ci-dessous
// Create DOM from URL or file
$html = file_get_html('http://www.google.com/');
// Find all images
foreach($html->find('img') as $element)
echo $element->src . '<br>';
// Find all links
foreach($html->find('a') as $element)
echo $element->href . '<br>';
J'ai utilisé preg_match pour le faire.
Dans mon cas, j’avais une chaîne contenant exactement une balise <img>
(et aucune autre balise) que j’avais obtenue de Wordpress et j’essayais d’obtenir l’attribut src
afin que je puisse exécutez-le à travers timthumb.
// get the featured image
$image = get_the_post_thumbnail($photos[$i]->ID);
// get the src for that image
$pattern = '/src="([^"]*)"/';
preg_match($pattern, $image, $matches);
$src = $matches[1];
unset($matches);
Dans le modèle permettant de saisir le titre ou l'alt, vous pouvez simplement utiliser $pattern = '/title="([^"]*)"/';
pour saisir le titre ou $pattern = '/title="([^"]*)"/';
pour saisir l'alt. Malheureusement, ma regex n'est pas assez bonne pour saisir les trois (alt/title/src) en un seul passage.
Voici une fonction PHP J'ai mis en parallèle toutes les informations ci-dessus dans un but similaire, à savoir ajuster les propriétés de largeur et de longueur de balise d'image à la volée ... un peu maladroit, peut-être, mais semble fonctionner de manière fiable:
function ReSizeImagesInHTML($HTMLContent,$MaximumWidth,$MaximumHeight) {
// find image tags
preg_match_all('/<img[^>]+>/i',$HTMLContent, $rawimagearray,PREG_SET_ORDER);
// put image tags in a simpler array
$imagearray = array();
for ($i = 0; $i < count($rawimagearray); $i++) {
array_Push($imagearray, $rawimagearray[$i][0]);
}
// put image attributes in another array
$imageinfo = array();
foreach($imagearray as $img_tag) {
preg_match_all('/(src|width|height)=("[^"]*")/i',$img_tag, $imageinfo[$img_tag]);
}
// combine everything into one array
$AllImageInfo = array();
foreach($imagearray as $img_tag) {
$ImageSource = str_replace('"', '', $imageinfo[$img_tag][2][0]);
$OrignialWidth = str_replace('"', '', $imageinfo[$img_tag][2][1]);
$OrignialHeight = str_replace('"', '', $imageinfo[$img_tag][2][2]);
$NewWidth = $OrignialWidth;
$NewHeight = $OrignialHeight;
$AdjustDimensions = "F";
if($OrignialWidth > $MaximumWidth) {
$diff = $OrignialWidth-$MaximumHeight;
$percnt_reduced = (($diff/$OrignialWidth)*100);
$NewHeight = floor($OrignialHeight-(($percnt_reduced*$OrignialHeight)/100));
$NewWidth = floor($OrignialWidth-$diff);
$AdjustDimensions = "T";
}
if($OrignialHeight > $MaximumHeight) {
$diff = $OrignialHeight-$MaximumWidth;
$percnt_reduced = (($diff/$OrignialHeight)*100);
$NewWidth = floor($OrignialWidth-(($percnt_reduced*$OrignialWidth)/100));
$NewHeight= floor($OrignialHeight-$diff);
$AdjustDimensions = "T";
}
$thisImageInfo = array('OriginalImageTag' => $img_tag , 'ImageSource' => $ImageSource , 'OrignialWidth' => $OrignialWidth , 'OrignialHeight' => $OrignialHeight , 'NewWidth' => $NewWidth , 'NewHeight' => $NewHeight, 'AdjustDimensions' => $AdjustDimensions);
array_Push($AllImageInfo, $thisImageInfo);
}
// build array of before and after tags
$ImageBeforeAndAfter = array();
for ($i = 0; $i < count($AllImageInfo); $i++) {
if($AllImageInfo[$i]['AdjustDimensions'] == "T") {
$NewImageTag = str_ireplace('width="' . $AllImageInfo[$i]['OrignialWidth'] . '"', 'width="' . $AllImageInfo[$i]['NewWidth'] . '"', $AllImageInfo[$i]['OriginalImageTag']);
$NewImageTag = str_ireplace('height="' . $AllImageInfo[$i]['OrignialHeight'] . '"', 'height="' . $AllImageInfo[$i]['NewHeight'] . '"', $NewImageTag);
$thisImageBeforeAndAfter = array('OriginalImageTag' => $AllImageInfo[$i]['OriginalImageTag'] , 'NewImageTag' => $NewImageTag);
array_Push($ImageBeforeAndAfter, $thisImageBeforeAndAfter);
}
}
// execute search and replace
for ($i = 0; $i < count($ImageBeforeAndAfter); $i++) {
$HTMLContent = str_ireplace($ImageBeforeAndAfter[$i]['OriginalImageTag'],$ImageBeforeAndAfter[$i]['NewImageTag'], $HTMLContent);
}
return $HTMLContent;
}
Voici la solution, en PHP:
Il suffit de télécharger QueryPath, puis procédez comme suit:
$doc= qp($myHtmlDoc);
foreach($doc->xpath('//img') as $img) {
$src= $img->attr('src');
$title= $img->attr('title');
$alt= $img->attr('alt');
}
Ça y est, vous avez terminé!
J'ai lu les nombreux commentaires sur cette page qui se plaignent que l'utilisation d'un analyseur dom est une surcharge inutile. Cela coûte peut-être plus cher qu'un simple appel regex, mais le PO a déclaré qu'il n'y avait aucun contrôle sur l'ordre des attributs dans les balises img. Ce fait conduit à une convolution inutile du motif regex. De plus, l'utilisation d'un analyseur dom offre les avantages supplémentaires de lisibilité, de maintenabilité et de connaissance de dom (regex n'est pas sensible à dom).
J'aime regex et je réponds à beaucoup de questions sur les regex, mais quand on traite avec du HTML valide, il y a rarement une bonne raison de regex avec un analyseur.
Dans la démonstration ci-dessous, voyez comme DOMDocument est facile et propre à gérer les attributs de balises img dans n’importe quel ordre, avec une combinaison de guillemets (et pas de guillemets du tout). Notez également que les balises sans attribut ciblé ne perturbent pas du tout - une chaîne vide est fournie en tant que valeur.
Code: ( Demo )
$test = <<<HTML
<img src="/image/fluffybunny.jpg" title="Harvey the bunny" alt="a cute little fluffy bunny" />
<img src='/image/pricklycactus.jpg' title='Roger the cactus' alt='a big green prickly cactus' />
<p>This is irrelevant text.</p>
<img alt="an annoying white cockatoo" title="Polly the cockatoo" src="/image/noisycockatoo.jpg">
<img title=something src=somethingelse>
HTML;
libxml_use_internal_errors(true); // silences/forgives complaints from the parser (remove to see what is generated)
$dom = new DOMDocument();
$dom->loadHTML($test);
foreach ($dom->getElementsByTagName('img') as $i => $img) {
echo "IMG#{$i}:\n";
echo "\tsrc = " , $img->getAttribute('src') , "\n";
echo "\ttitle = " , $img->getAttribute('title') , "\n";
echo "\talt = " , $img->getAttribute('alt') , "\n";
echo "---\n";
}
Sortie:
IMG#0:
src = /image/fluffybunny.jpg
title = Harvey the bunny
alt = a cute little fluffy bunny
---
IMG#1:
src = /image/pricklycactus.jpg
title = Roger the cactus
alt = a big green prickly cactus
---
IMG#2:
src = /image/noisycockatoo.jpg
title = Polly the cockatoo
alt = an annoying white cockatoo
---
IMG#3:
src = somethingelse
title = something
alt =
---
L'utilisation de cette technique dans un code professionnel vous laissera un script clair, moins de problèmes et plus de collègues qui souhaiteraient que vous travailliez ailleurs.