Jump to content

preg_replace_callback

- - - - -

  • Please log in to reply
3 replies to this topic

#1
Vaielab

Vaielab

    Programming God

  • Members
  • PipPipPipPipPipPipPip
  • 547 posts
Hello,

As you might know, I suck at regex.. but I have to use it. And I'm hoping you could help me.

So this is my problem.
Before sending the html code to the client, I would like to pass it into a function that will modify it a little bit.
For every <form> tag I would like to add a input type hidden in it.
I need to use preg_replace_callback since the value of the hidden will change for every form.
The value is calculed with the action of the form, so it has to be sended as parameter to the function.
A second parameter might be sended depending if he exist inside the <form> tag.
The second parameter has to be removed (if he existed)

So this is what I have so far (not much, but can help)

preg_replace_callback('/(<form.*.>)/', 'FN_Hidden::createHidden', $this->childData)

Right now, I find every <form action=...> but not if the tag dosen't have space in it like so <form>
And I don't send any parameters to the function.

I know, this might be a lot to ask, so I don't ask you to solve everything
But if you could just guide me in the right direction, I should be able to do the rest

Thank you

#2
Alexander

Alexander

    It's Science!

  • Moderators
  • 4,124 posts
  • Location:Vancouver, Eh! Cleverness: 200
Forgive me if I am sending you off on the wrong direction, if it is more complex than this, however DOM is a valid option this specific case:

<?php
$html="<html>
  <body>
     <form>...
     <form >...
     <form action='foo'  hidden=1 />
     <form hidden=0>...
  </body>
</html>";

// Create DOM resource
$dom = new DOMDocument();
$dom->loadHTML($html);

// Evaluate an X path
$xpath = new DOMXPath($dom);
// Load all forms within body (if they are all within some element)
$forms = $xpath->evaluate("/html/body//form");

for ($i = 0; $i < $forms ->length; $i++) {
        $form = $forms ->item($i);

        // Get attribute
        $url = $form ->getAttribute('hidden');

        if($hidden != "1") {
          // Set attribute
          $form ->removeAttribute('hidden');
          $form ->setAttribute("hidden", "1");
      }
}

// Retrieve result of transformation
$html_new = $dom->saveHTML();

echo $html_new;

?>

Achieves basically this result (can be formatted):
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<html><body>
     <form hidden="1">...</form>
     <form hidden="1">...</form>
     <form action="foo" hidden="1"></form>
     <form hidden="1">...</form>
</body></html>


Of course you can check any attribute you wish within the loop, to not change an existing hidden, or not change it if an action is something specific. I was unsure of what you had meant.

Alexander.
Be sure to read the updated FAQ! || Health is achieved through the same 10,000 steps.
If a suggested code/method fails, informing us is less important than telling us why or what errors occurred.

#3
Vaielab

Vaielab

    Programming God

  • Members
  • PipPipPipPipPipPipPip
  • 547 posts
This is a great solution that I didn't though of.
But if I remember correctly, if html have error in it, DOM might fail, and return an empty string
But up to date, this is the best solution that I finded, thx for the help, I'm gonna continu looking at both possibilities, thx

---------- Post added at 10:06 AM ---------- Previous post was at 08:42 AM ----------

So I'm a little bit closer to the answer

preg_replace_callback('/(<form.*(action="([^"]*)"):?(expTime="([^"])")?.*>)/', 'FN_Hidden::createHidden', $this->childData)

If the form is this: <form action="abc" expTime="1522">

A var_dump of the first paremeter of FN_Hidden::createHidden will give me
array

  0 => string '<form action="abc" expTime="1522">' (length=34)

  1 => string '<form action="abc" expTime="1522">' (length=34)

  2 => string 'action="abc"' (length=12)

  3 => string 'abc' (length=3)

So I have my action url (index 3), I do not care about index 1 or 2, but don't know how to remove them
And I still don't get the expTime but I'll continu working on it!

---------- Post added at 10:08 AM ---------- Previous post was at 10:06 AM ----------

While doing my research, I read somewhere I could name the groups, if you could help me on that too, it could be great!

---------- Post added at 10:30 AM ---------- Previous post was at 10:08 AM ----------

Found it
If anyone is interesting here the answer:
$child = preg_replace_callback('/(<form(action="(?P<action>[^"]*)"|expTime="(?P<expTime>[^"]*)"|[^>])*[^>]*>)/', 'FN_Hidden::createHidden', $this->childData);

In FN_Hidden::createHidden I receive in the first parameter a array with index 0: the original string, index action: the action of the form, and index expTime: the expTime of the form

#4
Alexander

Alexander

    It's Science!

  • Moderators
  • 4,124 posts
  • Location:Vancouver, Eh! Cleverness: 200
I am glad you have found the answer, I do not think I could have come up with it.

As for broken HTML, it parses and cleans it up with its own Tidy-like interface. In my example there is very poor HTML of which it corrects if you have a look. It is wishful thinking that people start using these libraries, in the end it's hard to use them when external pages are hard to reach, malformed, messy, and regular expressions are the only "damage control" that is simple to resist changes.

Alexander.
Be sure to read the updated FAQ! || Health is achieved through the same 10,000 steps.
If a suggested code/method fails, informing us is less important than telling us why or what errors occurred.




1 user(s) are reading this topic

0 members, 1 guests, 0 anonymous users