-2

Possible Duplicate:
Redefine Built in PHP Functions

Howdy!

As my servers do not have a locally available "sendmail" command, and I have written an api-compatible replacement mail() function, how do I actually go about replacing PHP's built-in mail() function? (Or others; there are a few that need replacement beyond that.)

Thanks!

Community
  • 1
  • 1
amcgregor
  • 1,228
  • 12
  • 29
  • 4
    @GothAlice: First, sorry if you're not the one downvoting answers for telling you that this is a bad idea. But I would just like to point out that downvoting answers just because they don't tell you what you want to hear isn't good SO etiquette. (For the record, I also think that the people who are downvoting your original question in retaliation are being rather petty, but having said that I do kind of understand why they'd be annoyed at you). Please only downvote answers that are factually inaccurate, abusive or extremely badly thought out. – GordonM May 02 '11 at 20:54
  • @GordonM With the range of provably false assumptions and the opening line that assumes a perfect knowledge of my problem domain, the philosophical "you shouldn't do this" answer happens to be factually inaccurate, thus my down-voting of it. Thank you, though, for your answer. Hopefully my assumption counter-points more clearly illustrate what the rationale for replacing the built-in was, even though _it isn't needed to answer this question_. – amcgregor May 02 '11 at 21:36
  • 3
    @Alice: Well the onus is on the question asker to provide enough information for an answer that meets their needs to be given. If you don't point out in your question that just using a different name for your mail sending function isn't an option, you'll get a load of answers telling you not to override the default mail function. If we fail to understand the problem domain then you need to specify it in more detail. – GordonM May 02 '11 at 21:58
  • 75% got it as-is. I may have had more success with _less_ detail; something like "How do I replace a built-in function with one of my own?" would have been better, then there wouldn't have been the needless discussion of alternate e-mail delivery options, which is unrelated to the underlying question, and a topic with which I am intimately familiar, having written a few. Lesson learned. ;) – amcgregor May 02 '11 at 22:49
  • 2
    @GothAlice: So you are actually down-voting those who spent more time trying to give you correct answers as well as additional information regarding best practices... Humm, I hope I remember not to answer any of your questions again, lesson learned. – Alix Axel May 02 '11 at 23:52
  • @Alix Any additional information I could give you (re: my experience programming, my understanding of best practices, the amount of consideration and consultation that went into the decision to use this as a solution, etc.) would remain utterly irrelevant to the question or the offering of answers to that question. **Practicality beats purity**; _unless you're willing to rewrite my clients' code for them, for free, every time they press 'publish'._ – amcgregor May 03 '11 at 06:07
  • 1
    @GothAlice: I am not, but a simple "I understand the implications of this" from you would probably have saved you all the trouble, we don't guess your level of expertise. IMHO asking for help and downvoting **correct and complete** answers is just arrogant. – Alix Axel May 03 '11 at 12:59
  • @Alix: A statement that "replacing mail is the wrong way to solve this problem" falsely assumes he knows what the problem _is_. He didn't; I didn't specify. He also didn't mention or link to the two actual solutions, thus his answer is _obviously_ not correct **or** complete. Down-voting an incorrect answer is hardly arrogant. – amcgregor May 03 '11 at 17:13
  • 1
    @GothAlice: None of the answers here pointed you to both solutions, you simply downvoted *all* the answers that said that this was a bad idea (which it is, specially when you ask for an "approved" solution), mine included. – Alix Axel May 03 '11 at 19:39

4 Answers4

7

Replacing mail is the wrong way to go about solving this problem.

If you need to send mail, but can't invoke the mail command, then you should use a third-party PHP mailing library that can use other methods. SwiftMailer is frequently recommended. It can use mail, invoke any sendmail-compatible binary or use an SMTP server directly. Further, it can be extended to send mail in any other way, thanks to a plugin architecture.

If you find yourself wanting to replace the PHP builtins, chances are that it's your code that is wrong, not PHP. Sure, some of the PHP builtins suck, but replacing the expected behavior of a function with your modified version is going to make future maintainers of your code want to murder you in your sleep.

Charles
  • 50,943
  • 13
  • 104
  • 142
  • Glad you have such in-depth knowledge of my use case that you can dismiss it completely. (That attitude problem is why I ended up asking on Stack Overflow instead of the PHP channel on IRC.) – amcgregor May 02 '11 at 17:28
  • 8
    @GothAlice, I make it common practice to suggest development processes that won't get people hurt. **Replacing PHP built-in functions is insanity**. The future maintainers of your code are going to seriously resent you. I can not urge you strongly enough to not attempt this. **Replacing PHP built-in functions is the wrong solution to this problem, period**. **There is *no* valid use case for this. *Ever*.** – Charles May 02 '11 at 17:43
  • 6
    @Charles: Couldn't agree more. What happens when someone looks at the code and can't figure out why mail() isn't behaving like the PHP docs say it should behave? – GordonM May 02 '11 at 18:01
  • 3
    I see only one person who has an attitude problem here, and it's not @Charles – Pekka May 02 '11 at 19:10
  • @GordonM Two options: a) mail() does not work; at all. b) mail() does work; as expected. Option B is what I'm attempting, and it requires replacing PHP's built-in version. @Pekka I ask a question, get three straight answers (covering two workable methods) and a meaningless philosophical debate from users who have no understanding of the problem at hand. I didn't ask for a debate on the "correctness" of doing this. I asked for a) the easiest, or b) an "approved" way to replace a builtin. Pretty clear question. Give https://gist.github.com/701213 a gander or two. – amcgregor May 02 '11 at 19:43
  • 5
    @GothAlice, please be aware that the posted solutions for replacing PHP functions require installing binary PECL extensions. You *won't* be able to do that on shared hosting. Runkit is highly experimental, and APD is a debugger. No shared hosting company would ever consider installing those. **On the other hand, you *will* be able to install a well-regarded, well-tested, highly flexible third-party mailing library on shared hosting.** `mail` sucks, and this is exactly why these libraries exist. – Charles May 02 '11 at 19:47
  • 1
    @GothAlice, you have fallen into a common programmer trap. You've encountered a problem, and have come up with a solution, and then you've asked how to implement that. What you should be doing is asking why the problem is happening to begin with, and whether your solution is going to work. The *problem* is solvable, and has been solved over and over by many people. The solution *you chose* is inappropriate and will cause future maintainers of your code to think that you are a complete raving lunatic. From your comments, you *will* have future maintainers of this code. – Charles May 02 '11 at 19:54
  • 3
    @GothAlice, you also continue to accuse me of making "false assumptions," but you have failed to mention at any point what makes your problem so completely *special* that you would consider *breaking developer expectations* and using *experimental language extensions* instead of taking the common, well-tested, well-supported route. You should probably read up on [the principal of least astonishment](http://en.wikipedia.org/wiki/Principle_of_least_astonishment). Replacing PHP builtins is going to be damned astonishing. Using a third-party library is going to be a yawnfest. – Charles May 02 '11 at 19:58
  • 5
    @GothAlice: Saying "arrogant and unhelpful" and "get off your high horse" to people you're asking for free help in solving problems is probably not a good idea. Please read the [FAQ](http://stackoverflow.com/faq) if you haven't already done so, particularly the section on how you should treat others. This site works by people being respectful and polite to each other. If you don't want to abide by the guidelines, perhaps you should seek help elsewhere. Thanks for your cooperation. – Ken White May 02 '11 at 20:01
  • @Charles Assumption 1: I just need to send mail. **False.** I _actually_ need to allow code which uses `mail()` to operate properly without modification. Assumption 2: The `mail()` function works, or, alternatively, I have access to a `sendmail` binary; I do not. Assumption 3: I have code. **False.** I'm attempting to get others' code to work. Assumption 4: I want `mail()` to do something different than what it should. **False.** I want `mail()` to operate normally, just using SMTP behind-the-scenes. Assumption 5: There is no use case for replacing functions. **Obviously false.** – amcgregor May 02 '11 at 21:02
  • 2
    @GothAlice: You can write a function that sends mail and that is not called mail(), you know. In fact if you're implementing mailing yourself then that's exactly the route you should take so that when someone else (or you in several months' time) come to look at the code again they can spot straight away that you've implemented your own mail sending functionality instead of using mail(). BTW, the people who are telling you not to override mail() are doing so for very good reasons. They're just trying to save you from making a mistake. There is no need to be rude about it. – GordonM May 02 '11 at 21:02
  • Assumption 6: I'm running on shared hosting. I _am_ the shared hosting. Assumption 7: I have control over the code being run. I do not; random clients upload random code to their sites. Assumption 8: I haven't attempted alternatives. I have, including user education. Replacing a builtin with a function that has an identical runtime spec is actually more cost effective. Assumption 9: I'm an idiot. In fact, I have not fallen prey to any traps, I just have a use case outside of your range of experience. – amcgregor May 02 '11 at 21:06
  • Assumption 10: My `mail()` replacement is "astonishing". Not at all; it conforms to the **exact same API**, return values, and handles expected arguments in exactly the correct way. The only difference is that it uses PECL's mailer to send the message via SMTP, and uses a magical INI file I, as a host, add to each account to pull SMTP settings from. Code that uses mail() continues to work without a care in the world. (Or any indication that something other than the stock default `mail()` call is going on.) Not astonishing at all, actually. – amcgregor May 02 '11 at 21:12
  • 2
    Wait wait wait. *You* control the server? Yet `mail` is broken? That says volumes. We're done here. You go have fun with that. – Charles May 02 '11 at 21:13
  • Apologies, @Ken White, but when I can count 14 false assumptions littered amongst philosophical absolutisms, I get a bit… unhappy. When I ask a question, I want the answer, not debate, unless such debate also contains the answer. @GordonM You also seem to suffer the assumption problem, though you at least had a valid answer, too. Hopefully my previous "assumption" comments will help clear things up a bit. – amcgregor May 02 '11 at 21:21
  • @Charles Cute. Give me a way for the real `mail()` built-in to utilize SMTP with per-user authentication settings, correct (defaulted) `Date:` header, configurable (via INI, the same as the authentication settings) default `From:` header, and the ability to override SMTP host:port and authentication in the call, then get back to me. Classifying this answer and its comments as "help" (no matter how free) would be stretching things. – amcgregor May 02 '11 at 21:27
  • 1
    @GothAlice, when confronted with things about PHP that suck, the normal thing is to work around the suckitude by using a library. In this specific case, there are no less than three different useful, modern, third-party libraries that do everything you've just asked for, short of replacing *a built-in function*. It's clear that you have stubbornly made up your mind that you *are* going to go down this insane road, so there is no further reason to continue this little spat. As a tip, if you'd have explained everything you just explained *up-front*, you would have gotten far more useful answers. – Charles May 02 '11 at 22:02
  • @Charles The other actual answers were the answers I was looking for, with the same minimal starting information… 2/3 isn't bad, really. ("I have an API compatible replacement, how do I shove it in there?") There was no need for me to elaborate… except to identify in which ways you assumed incorrectly. If stubbornly solving my real problem gets me a) happy customers, b) paid, c) home in time for dinner, I'll stubbornly solve my problem. It's not even that I'm being stubborn; _you just haven't suggested anything akin to a solution to my problem yet._ – amcgregor May 02 '11 at 22:43
6

You could in theory use the APD override_function to do this, but I would really really REALLY advise against doing that.

Is there any reason you can't just give your function a different name and use that name instead of mail?

If you absolutely insist, then http://php.net/manual/en/function.override-function.php

GordonM
  • 31,179
  • 15
  • 87
  • 129
  • 1
    And this was downvoted because? It's a valid answer and will work, and it also points out that doing it this way is not a good idea. – GordonM May 02 '11 at 18:00
4

Check this out: http://php.net/manual/en/function.override-function.php

bool override_function ( string $function_name , string $function_args , string $function_code ) 

Overrides built-in functions by replacing them in the symbol table.

PiZzL3
  • 2,092
  • 4
  • 22
  • 30
2

runkit_function_redefine(), but I wouldn't call it the "approved" way, since this shouldn't be done.

Alix Axel
  • 151,645
  • 95
  • 393
  • 500