简体   繁体   中英

preg_match_all between dynamic tags

I would like to grab each of my virtual hosts configurations and put them in an array using preg_match_all so I can extract information from each of them, for example...

$vHostConfig = '    <VirtualHost *:80>
        ServerName localhost
        DocumentRoot c:/wamp/www
        <Directory  "c:/wamp/www/">
           Options +Indexes +Includes +FollowSymLinks +MultiViews
           AllowOverride All
           Require local
        </Directory>
    </VirtualHost>
    <VirtualHost *:8080>
        ServerName testing.com
        DocumentRoot c:/wamp/www/testing.com
        <Directory  "c:/wamp/www/testing.com">
           Options +Indexes +Includes +FollowSymLinks +MultiViews
           AllowOverride All
           Require local
        </Directory>
    </VirtualHost>
    <VirtualHost 127.0.0.1:80>
        ServerName testing2.com
        DocumentRoot c:/wamp/www/testing2.com
        <Directory  "c:/wamp/www/testing2.com">
           Options +Indexes +Includes +FollowSymLinks +MultiViews
           AllowOverride All
           Require local
        </Directory>
    </VirtualHost>
#    <VirtualHost *:80>
#        ServerName testing3.com
#        DocumentRoot c:/wamp/www/testing3.com
#        <Directory  "c:/wamp/www/testing3.com">
#            Options +Indexes +Includes +FollowSymLinks +MultiViews
#            AllowOverride All
#            Require local
#        </Directory>
#    </VirtualHost>';

preg_match_all(<<what to put here>>, $vHostConfig, $vHostConfigMatches);

I would like to grab only the active configurations without a # at the beginning of the line meaning I should have three strings starting with <VirtualHost and finishing with </VirtualHost> in $vHostConfigMatches array. Is this possible?

You could use this regular expression:

preg_match_all('/^\h*<VirtualHost.*?>.*?\R\h*<\/VirtualHost>/sm',
               $vHostConfig, $vHostConfigMatches);  

Note that the array $vHostConfigMatches will have an additional nesting level, so just take the first one with reset :

print_r(reset($vHostConfigMatches));

You could split it by line: $lines = explode(PHP_EOL, $vhostConfig);

Filter out all of the commented lines: $lines = array_filter($lines, function ($ele) { return substring($ele, 0) != "#"; });

Put it back together: $vhostConfig = implode(PHP_EOL, $lines);

Then use a regex to pull each virtual host (you may want something more precise: preg_match_all("@<VirtualHost [\\d\\.\\*:]+>(.*?)</VirtualHost>@", $vhostConfig, $vhostConfigMatches);

Untested, but should give you the idea. This also has the benefit of ignoring any commented line in a valid virtualhost

Although the @trincot's answer works fine, it uses the .*? (lazy) quantifier which makes the regex engine highly active: this regex101 shows it takes 950 steps in this example.

So I think that, even if it seems a bit more complicated, this simple PHP snippet would run faster:

$result = array_reduce(
  explode(PHP_EOL, $str),
  function($result, $line) {
    if (trim($line[0]) <> '#') {
      if (strpos($line, '<VirtualHost') !== false) {
        $result[] = $line;
      } else {
        $result[count($result) - 1] .= $line;
      }
    }
    return $result;
  },
  []
);

At once, it merely:

  • turns the original string into an array of lines
  • drop any comment
  • populates the needed result as expected

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM