Menu
Is free
registration
home  /  ON/ Irrevocable success php. A Simple Example Using PHP and AJAX

Irrevocable success php. A Simple Example Using PHP and AJAX

Greetings, dear friend!

"What is success in life for you ???"

Please, think about it, stop for a minute.

Okay, now let me help you. What is not a success, I wrote in the previous mailing list. Let's discard these concepts right away.

Success is peace of mind.
Success is being happy.
Success is the realization of oneself and the disclosure of one's potential.
Success is fulfillment in life.
Success is doing what you love, which ignites you and you can do it around the clock.
Success is giving yourself to others and making the world a better place and happier other people.
.

Success is inextricably linked to the state of mind. Our soul came into this world to enjoy and realize itself, and we (our mind, our body, our consciousness) must support it in this. When our soul creates and realizes itself, we feel happy. When we feel and see that the creation of our soul and what we do is of great benefit to other people, we feel bliss. This is what is called success. Success is the fulfillment of life.

Any realization of the talents of the soul is possible only thanks to other people... The soul does not create for itself. She creates for others - to help them and make the lives of others fulfilled and give them a piece of her happiness. A happy person passes on a piece of his happiness to others, an unhappy person passes on his unhappiness to others. Avoid unhappy people!

If suddenly at the moment all people disappear, self-realization will become impossible - what is the point in writing books, because no one will read them, what is the point in creating new models of clothes, because no one will wear them, what is the point in building new houses, in which no one will live?

Obviously it doesn't make sense.

Here it appears the double nature of success: the soul creates and realizes itself, and also helps other people to become happier.
The most precise definition success that I could give would sound like this: success is the realization of your true talents, which make our world better, more perfect, and people happier.

I want you to deeply realize that people who live only for themselves and collect wealth only for themselves are unhappy... They collect this wealth in order to fill the spiritual void that has formed as a result of a meaningless life. But this void can only be filled with love, bringing value to other people. The soul is happy when it gives itself without excess to make this world a better place. And what is the point in all those riches that a person has collected when he passes away, because we are not durable. The soul comes to create value, to realize itself and then returns "home". If she does not create this value, but does something else, she feels bad. She feels that she has come into this world and is not doing what she wants. And the reason for this is our mind - it is blinded by "success" in the general understanding of this word. He chases after the illusory, and when he achieves this, if at all, he realizes the meaninglessness of what he has achieved.

And what is success in general understanding?
- wealth (money, material things)
- glory, power, popularity
- status

But look it all comes from the ego. A person wants to feel his own significance, but he does not understand that wealth, fame, status is an illusion. They are like sea water, which no matter how much you drink, you will never satisfy your thirst. Therefore, people all their life and chase after them. They think that I’ll earn so much money and I’ll be happy, that I’ll go to the level of income of $ 100,000 a year and then I’ll be happy, when I go on stage and sing I’ll be happy, I’ll get married, I’ll have children ... you can check it out, but I can say with 100% certainty that you will not be happy. Moreover, your level of happiness will become even lower. You move away from your calling, and realizing this, the soul becomes even more unhappy. The more wealth, fame, status you receive, the more control over life the mind takes and the further the role of the soul is pushed back. But true happiness comes from the soul!!!

Success is harmony between soul and mind. The role of reason is to to help soul to self-actualize. We are prioritizing wrong. We put the short-lived body and material things in the first place, and we put the immortal soul and inexhaustible wealth in the last place. The Bible says, "gather wealth in heaven, not earth." Our body is a vehicle for the soul... The soul is connected with the Higher Mind and only it is able to understand what is needed for this world. The universe encourages people who go their own way... Your path is the least energy-consuming, and in our world everything flows along the path of least resistance. I always say that success is a normal course of events. Failure is a deviation from the norm. If now you are not as successful as you want it, then you are not doing what you are meant to do. Soul and mind are at odds. And the more this discord, the more unhappy the person is.

But do not think that I am saying that a person does not need material things. Very much even necessary. And here's why: when a person has no money, he is forced to go to work and engage in some kind of "stupidity". A person spends 10 hours a day in order to earn money, but by doing this he does not realize himself. The chef is the person who realizes himself at the expense of you. (I say how it happens in most cases. Most people hate their jobs, but they work because they need money to survive).

Material things create comfort for the soul. Material things equip this world for the soul. It is much more pleasant for the soul to create masterpieces in places that inspire it. It is much better to paint a picture in a house by the sea than in a "cesspool". The soul needs peace and comfort in order to create. But what peace can there be if the family does not have enough money and every day the husband and wife quarrel about this.

The soul needs time to express itself. Only after some time has passed, the value created by the soul can be sold and sold hundreds, or even thousands of times more expensive than a person gets at work. But it takes time to create such value. Personally, it took me 5 months to come up with a meager income. After 8 months, my site began to generate income that a poor family could already live on. And only 17 months later, my site began to generate income, which will already replace income from a very high-paying job.

It took 17 months to replace the job. But now I'm free! I do what I love and this is just the beginning. There are no limits for my dreams - and therefore there are no limits for me. When you go about your business, your income is limited only by your imagination and nothing more. Who at work makes $ 1,000,000 a year? Yes, there may be one. But doing your own thing, even this is not a chapel.
The material is important, but only in order to satisfy the needs to live.

I'll be honest: not receiving income, it is harder to create and create masterpieces... The mind constantly says: "what you do is good, but what are we going to live for?" And this question constantly and strongly distracts from creativity. He takes away our happiness. In order to turn off this dialogue, your favorite pastime must bring money. Of course, the mind then begins to ask other questions, but how more money brings what you love, the less painful and distracting these issues become.

Often people work at work, earn money, but still have a hobby. What is a hobby?
A hobby is a hobby that does not generate income. But why not turn a hobby into a job? The happiest people are those whose hobby is work.... They are non-stop doing what they love.
Everything I talk about, about work, about money, I want to convey to you two important thoughts: 1) Soul and mind must be in harmony
2) The intangible should always come first

The focus should only be on the intangible! Material to be attached as a consequence... Here are the right priorities in life:
happiness -> health -> wealth And many people live according to the scheme
wealth-> health-> happiness
And even worse, there are people who live according to the pattern
wealth-> wealth-> wealth

No wonder they are not happy. These people have millions, but they have no friends, they have family problems. They have problems in relationships with people. Because they think that all the people who surround them are with them only because of their money and nothing else. I do not know about you, but I would not want such happiness. When the priorities in life are set correctly, wealth arises as a result. There is no point in focusing on it. High levels of happiness and health inevitably lead to high levels of income.

Material things and our wealth can only serve as an addition to our happiness. They cannot serve as a foundation. What is the foundation, we have already discussed with you above.

The set of key / value pairs that customize the request AJAX. All parameters are optional... It is allowed but not recommended to set a default value for any parameter using the $ .ajaxSetup () method.
Method $ .ajax () supports the following parameters:

    accepts(default: depends on dataType).

    Type: PlainObject.
    The set of key / value pairs that are sent to Accept request header. This header tells the server what kind of response the request will accept in response. Note that the value of the parameter specified in dataType(the data type that we expect from the server) is matched with the one specified in the parameter. In addition, for the correct processing of the response from the server, it is necessary in the parameter converters specify a function that returns the converted response value. For example: $ .ajax (( accepts: (mycustomtype: " application / x-some-custom-type" } , // specify how to process the response converters: ("text mycustomtype": function ( result) { // return the transformed response value return newresult; )), // Expected data type ("mycustomtype") dataType: "mycustomtype"));

    async(default: true).

    Type: Boolean.
    By default, all requests are sent asynchronously, if you need to organize synchronous requests, then set this parameter to false. Please note that cross-domain requests and element, parameter dataType which matters "jsonp" do not support synchronous requests. Please note that using synchronous requests, you can temporarily block the browser by disabling any actions while the request is active.

    beforeSend... Type: Function (jqXHR jqXHR, PlainObject settings).
    Callback function that will be called before making the AJAX request. This function allows you to modify the jqXHR object (in jQuery 1.4.x the XMLHTTPRequest object) before it is sent. The jqXHR object is an add-on that extends the XMLHttpRequest object, the object contains many properties and methods that allow you to get more full information about the server's response, as well as the object contains Promise methods. If the function beforeSend returns false, then the AJAX request will be canceled. From version jQuery 1.5 function beforeSend will be called regardless of the request type.

    cache(default: true, for dataType "script" and "jsonp" false).

    Type: Boolean.
    If set to false, this will cause the requested pages to not be cached by the browser. Note that false will only work correctly with HEAD and GET requests.

    complete.

    Type: Function (jqXHR jqXHR, String textStatus).
    A function that is called when the request ends (the function is executed after AJAX events "success" or "error"). Two parameters are passed to the function: jqXHR(in jQuery 1.4.x object XMLHTTPRequest) and a line corresponding to the request status ( "success", "notmodified", "nocontent", "error", "timeout", "abort", or "parsererror"). Since jQuery 1.5, the parameter complete can take an array of functions that will be called in turn.

    contents.

    Type: PlainObject.
    An object consisting of string / regular expression pairs that define how jQuery will parse (parse) the response depending on the content type. Added in jQuery 1.5.

    contentType(default: "application / x-www-form-urlencoded; charset = UTF-8").

    Type: Boolean, or String.
    Determines the type of content that is specified in the request when sending data to the server. Since jQuery 1.6 it is allowed to specify the value false, in which case jQuery does not pass the field in the header Content-Type at all.

    context.

    Type: PlainObject.
    When AJAX callbacks are executed, their execution context is the window object. Parameter context allows you to set up the execution context of a function in such a way that $ (this) will refer to a specific DOM element, or object. For example: $ .ajax (( url: "test.html", context: $ (". myClass"), // new context of function execution success: function () ( // if the request is successful, call the function$ (this) .html ("Everything is OK"); // add text content to the element with class.myClass } } );

    converters

    Default values:
    ("* text": window.String, // any type to text"text html": true, // text in html "text json": jQuery.parseJSON, // text in JSON "text xml": jQuery.parseXML // text in XML) Type: PlainObject.
    An object containing the data type to convert and how to convert it. The value of each transformer is a function that returns the transformed response value. Added in jQuery 1.5.

    crossDomain(default: false for requests within the same domain, true for cross-domain requests).

    Type: Boolean.
    If you want to make a cross-domain request while on the same domain (for example, a jsonp request), then set this parameter to true. This will allow, for example, to redirect the request to another domain from your server. Added in jQuery 1.5.

    Type: PlainObject or String or Array.
    Data to be sent to the server. If they are not a string, they are converted to a query string. For GET the query string will be appended to the URL. In order to prevent automatic processing, you can use the parameter processData with the value false. If data is transferred as part of an object, then it must consist of key / value pairs. If the value is an array, then jQuery serializes multiple values ​​with the same key (depending on the value of the parameter traditional which allows us to use the traditional serialization type based on the $ .param method).

    dataFilter.

    Type: Function (String data, String type) => Anything.
    The function is called after the successful execution of the AJAX request and allows you to process the "raw" data received from the server response. The data must be returned immediately after processing. The function takes two arguments: data- data received from the server as a string and type- the type of this data (parameter value dataType).

    dataType(default: xml, json, script, or html).

    Type: String.
    Defines the type of data that you expect to receive from the server. If no datatype is specified, then jQuery will try to determine it based on the MIME type from the answer ( XML type of MIME will result in XML, as of jQuery 1.4 json will give an object JavaScript, script will execute the script and everything else will be returned as a string).

    Basic types (the result is passed as the first argument to the callback function success):

    • "xml"- returns XML a document that can be rendered with jQuery.
    • "html"- returns Html as plain text, tags

      The easiest way to work with AJAX Is to connect the framework jQuery, which I actually did. jQuery provides us with an easy-to-understand and easy-to-use syntax for sending AJAX requests, why not take advantage of this?

      Js script creation

      The syntax for the validate.js file is

      $ (document) .ready (function () (var email = ""; $ ("# email"). keyup (function () (var value = $ (this) .val (); $ .ajax ((type: "POST", url: "email.php", data: "email =" + value, success: function (msg) (if (msg == "valid") ($ ("# message"). Html (" This Email can be used.This Email is already taken.");))));)); $ (" # submit "). click (function () (if (email ==" ") (alert (" Please, put data to all email ");) else ( $ .ajax ((type: "POST", url: "email.php", data: "add_email =" + email, success: function (msg) ($ ("# message"). html (msg);)) );)));));

      Php handler

      This script will receive POST request from the client, process it and return the result. AJAX reads the result and makes a decision based on it.
      The syntax for the email.php file is

      $ connection = mysqli_connect ("localhost", "email", "email", "email"); if (isset ($ _ POST ["email"]) && $ _POST ["email"]! = "") ($ email = $ _POST ["email"]; $ email = mysqli_real_escape_string ($ connection, $ email); if (! filter_var ($ email, FILTER_VALIDATE_EMAIL)) (echo "invalid";) else ($ sql = "SELECT id FROM email WHERE email =" $ email ""; $ result = mysqli_query ($ connection, $ sql); if ( mysqli_num_rows ($ result) == 1) (echo "invalid";) else (echo "valid";))) if (isset ($ _ POST ["add_email"]) && $ _POST ["add_email"]! = "" ) ($ email = mysqli_real_escape_string ($ connection, $ _ POST ["add_email"]); $ sql = "INSERT INTO email (email) VALUES (" $ email ")"; if (mysqli_query ($ connection, $ sql)) ( echo Success";) else (echo" Error"; } }

      In our php script, the most common code that processes a post request and prints some text on the page. As a result AJAX sends a request php script, the script processes it and produces the result, AJAX reads the result and changes the page in real time.

      AJAX passes the POST request to the script through this piece of code:

      $ .ajax ((type: "POST", url: "email.php", data: "email =" + value, success: function (msg) (if (msg == "valid") ($ ("# message ") .html (" This Email can be used."); email = value;) else ($ (" # message "). html (" This Email is already taken."); } } });

      type - The type of request, POST or GET. In our case, POST;
      url - the address of the script to which the request is sent;
      data - data that is transmitted in the request;
      success - what to do as a result of successful execution of the request. In our case, the function is called;

      In the script itself, a check for the presence of email in the database is performed each time a character is entered into the email field. In the script, the $ ("# email"). Keyup (function () ()); which checks for a key press in the field with id = "email".
      As you can see, the code is quite simple and does not require particularly great skills to understand, everything is tied to handling keyup () events - pressing a key, click () - clicking an element. Followed by AJAX request and response from the script. Thus, using php and ajax, you can get almost endless possibilities for creating interactive pages.
      This code does not claim to be of high quality, but if you develop it, add the correct validations at the client and server level, enter css, then you can quite use it in your projects.
      If you have any questions, do not hesitate to write comments.
      Have a nice day and see you soon 🙂

      Visa: Blaue Karte EU

      At the time of submission of documents 29 years old

      From Astrakhan

      Embassy city: Moscow

      University, specialty: Astrakhan State Technical University, Complex support information security automated systems

      Languages: English intermediate

      How it all began:

      The desire to move somewhere has been around for a long time. However, mainly warm countries with the sea were considered. Twice they seriously probed the soil with a view to moving to Montenegro or Bulgaria. As a result, at the last moment, for one reason or another, they changed their minds. The last time was in September 2014 after serious preparations for the sale of the car.

      In October, I accidentally saw an ad about the search for programmers with a relocation to Germany. At that time, I had no idea about the existence of the Blue Card and considered Germany a country with an incredibly tough migration policy towards non-EU citizens.

      With a certain amount of skepticism and mistrust, I wrote to Skype. On the other side of the screen, a recruiter (Alina), who is engaged in the selection of IT personnel, with the subsequent relocation to Germany, answered. At the time of our first communication, there was a recruitment of programmers for a large online store headquartered in Berlin. I sent in my resume and waited.

      After a while, Alina said that her colleague from Germany would talk to me to assess the level of language and adequacy. The interview is rather just a conversation with two logical tasks, it lasted 30 minutes on Skype. Then I was told to wait. A week or so later, the first technical interview was scheduled. The technical interview was also via Skype with one of the company's developers. In my opinion, it went quite well, but a week later I was told that I was not suitable. By the way, not a single candidate from Alina passed for certain reasons.

      How it all turned out:

      A little upset, but life goes on. And a few days later, Alina said that they had a new client from Stuttgart who was looking for developers, and an interview was scheduled for me. The first part of the interview is shared with the head of IT and HR departments. A general conversation about experience, myself and the company, a lot of laughter and jokes on both sides. Apparently, my humor was to my liking, so a few days later I was scheduled for a technical interview with a potential line manager. This part of the interview surprised me a little, because, as one of the candidates put it later, it was like "a conversation between two programmers over a beer." Later that evening, I received an invitation for a personal interview in the office.

      At that time, I did not have an open Schengen visa. The necessary documents were urgently collected. At the German Visa Application Center in Moscow, I applied for urgent visa and the very next day I took my passport with a visa. I applied for business visa by invitation that was sent to me from Esslingen is just a letter in which I am invited to communicate and where it is clearly stated that all financial issues with flights, transfers, meals and accommodation are undertaken by the company.

      Personal communication in the office took place with the three main IT leaders of the company. The first part is, again, just communication about experience, skills and general understanding of some issues. The second is at the computer. Honestly, very, very easy tasks of the "junior with testing experience" level :). The assignments were done. After that, lunch and immediately an offer in the form of two copies of work contracts (position Senior PHP Developer) signed by the company. I took some time to think and said that I would answer within a week.

      The decision was made and I began to prepare to apply for a visa.

      How we moved:

      The company paid for the flight for me and my family (wife and daughter 2.5 years old), rented an apartment for us for the first three months (in my case, an ideal place overlooking the central square of Marktplatz) and allocated a person to help for the first time. This is not a relocation agent in pure form, but we resolved all emerging issues through her. I was the first non-EU employee in the company, so many questions were honed on me. Now, besides me, another guy from Kiev works in the company (he flew in a month after me) and a developer from Odessa is preparing to move. All of them were also employed not without the help of Alina.

      Here I would like to say that I am very grateful to Alina, who solved all the questions that I had in the process of employment. I was very lucky that at all stages of employment and subsequent adaptation there was a person who was ready to help and solve the necessary issue.

      First I flew in alone, two weeks later my family arrived. On arrival, no one meets, for the first few days I lived in a hotel, waiting for my apartment to be vacated. They picked me up from the hotel and brought me to the place 🙂

      They took the necessary minimum from things.

      With ABH, everything went very quickly. All such issues were resolved jointly with a company employee. ABH appointed the term early enough after arrival, we submitted documents and three weeks later received our eAT cards.

      How we settled down:

      On this moment we live in Esslingen, an incredibly beautiful and clean town just 15 minutes from Stuttgart. We are not yet experiencing any discomfort due to not knowing the language, in most cases we can explain ourselves in English or, in extreme cases, with gestures. The only problem that exists at the moment is renting an apartment. There are very few offers and the demand is incredibly high. The housing situation in Stuttgart is a little easier, but I would like to stay in Esslingen.

      Brief summary with approximate dates:

      Mid october 2014- saw an ad about the search for programmers

      Late October - mid November - interviews with the first company

      Mid November - Late November - Interviews with my current company, receive an offer for a face-to-face interview

      January 20 - February 1 2015 g.- applying for a national visa, obtaining passports with visas

      ). The cloud is designed to run various PHP scripts on a schedule or via an API. Typically, these scripts process queues, and the load is "spread" across approximately 100 servers. Earlier, we focused on how the control logic is implemented, which is responsible for evenly distributing the load over such a number of servers and generating tasks on a schedule. But, in addition to this, we needed to write a daemon that would be able to run our PHP scripts in the CLI and monitor the status of their execution.

      It was originally written in C, like all the other demons in our company. However, we were faced with the fact that a significant part of the processor time (about 10%) was wasted, in fact, in vain: this is launching the interpreter and loading the "core" of our framework. Therefore, in order to be able to initialize the interpreter and our framework only once, it was decided to rewrite the daemon in PHP. We named it Php rock syd (by analogy with Phproxyd - PHP Proxy Daemon, the C daemon that we had before). It accepts requests to launch individual classes and does fork () for each request, and also knows how to report the execution status of each of the launches. This architecture is in many ways similar to the Apache web server model, when all initialization is done once in the "wizard" and the "children" are already handling the request. As an added bonus, we get the ability to enable the opcode cache in the CLI, which will work correctly since all children inherit the same shared memory area as the master process. To reduce delays in processing a start request, you can fork () in advance (prefork model), but in our case, fork () delays are about 1 ms, which is fine for us.

      However, since we update the code quite often, this daemon also needs to be restarted frequently, otherwise the code that is loaded into it may become outdated. Since each restart would be accompanied by a lot of errors of the form connection reset by peer, including denials of service for end users (the daemon is useful not only for the cloud, but also for part of our site), we decided to look for ways to restart the daemon without losing established connections... There is one popular technique used to make graceful reload for daemons: a fork-exec is done and a descriptor from the listen-socket is passed to the child. Thus, new connections are already accepted. new version demon, and the old ones are "modified" using the old version.

      In this article, we will look at a more complicated option. graceful reload: old connections will continue to be processed by the new version of the daemon, which is important in our case, because otherwise it will run the old code.

      Theory

      Let's think first: is it possible what we want to get? And if so, how can this be achieved?

      Since the daemon runs under Linux, which is POSIX compliant, the following options are available to us:

      1. All open files and sockets are numbers corresponding to the open descriptor number. Standard input, output, and error stream have descriptors 0, 1, and 2, respectively.
      2. No significant differences between open file, socket and pipe are not (for example, you can work with sockets using both read / write and sendto / recvfrom system calls).
      3. When the fork () system call is executed, all open descriptors are inherited, preserving their numbers and read / write positions (in files).
      4. When executing the execve () system call, all open descriptors are also inherited, and in addition, they are preserved. PID of the process and therefore attachment to their children.
      5. The list of open process descriptors is available from the / dev / fd directory, which on Linux is a symlink to / proc / self / fd.
      Thus, we have every reason to believe that our task is achievable, and without much effort. So let's get started.

      PHP patches

      Unfortunately, there is one small detail that complicates our work: in PHP there is no way to get the file descriptor number for streams and open the file descriptor by number (instead, a copy of the file descriptor is opened, which is not suitable for our daemon, since we are very carefully monitor open descriptors so as not to create leaks during restart and when starting child processes).

      First, we will make a couple of small patches to the PHP code to add the ability to get fd from a stream and make it so that fopen (php: // fd / ) did not open a copy of the handle (the second change is incompatible with the current PHP behavior, so you can add a new "address" instead, for example, php: // fdraw / ):

      Patch code

      diff --git a / ext / standard / php_fopen_wrapper.cb / ext / standard / php_fopen_wrapper.c index f8d7bda..fee964c 100644 --- a / ext / standard / php_fopen_wrapper.c +++ b / ext / standard / php_fopen_wrapper. c @@ -24.6 +24.7 @@ #if HAVE_UNISTD_H #include #endif + # include #include "php.h" #include "php_globals.h" @@ -296.11 +297.11 @@ php_stream * php_stream_url_wrap_php (php_stream_wrapper * wrapper, char * path, ch "The file descriptors must be non-negative numbers smaller than% d ", dtablesize); return NULL; ) - - fd = dup (fildes_ori); - if (fd == -1) (+ + fd = fildes_ori; + if (fcntl (fildes_ori, F_GETFD) == -1) (php_stream_wrapper_log_error (wrapper, options TSRMLS_CC, - "Error duping file descriptor% ld; possibly it doesn "t exist:" + "File descriptor% ld invalid:" "[% d]:% s", fildes_ori, errno, strerror (errno)); return NULL;) diff --git a / ext / standard / streamsfuncs. cb / ext / standard / streamsfuncs.c index 0610ecf..14fd3b0 100644 --- a / ext / standard / streamsfuncs.c +++ b / ext / standard / streamsfuncs.c @@ -24.6 +24.7 @ @ #include "ext / standard / flock_compat.h" #include "ext / standard / file.h" #include "ext / standard / php_filestat.h" + # include "ext / standard / php_fopen_wrappers.h" #include "php_open_temporary_file .h "#include" ext / standard / basic_functions.h "#include" php_ini.h "@@ -484.6 +485.7 @@ PHP_FUNCTION (stream_get_meta_data) zval * arg1; php_stream * stream; zval * newval; + int tmp_fd; if (zend_parse_parameters (ZEND_NUM_ARGS () TSRMLS_CC, "r", & arg1) == FAILURE) (return; @@ -502.6 +504.9 @@ PHP_FUNCTION (stream_get_m eta_data) add_assoc_string (return_value, "wrapper_type", (char *) stream-> wrapper-> wops-> label, 1); ) add_assoc_string (return_value, "stream_type", (char *) stream-> ops-> label, 1); + if (SUCCESS == php_stream_cast (stream, PHP_STREAM_AS_FD_FOR_SELECT | PHP_STREAM_CAST_INTERNAL, (void *) & tmp_fd, 1) && tmp_fd! = -1) (+ add_assoc_long (return_value, "fd_ mode", tmp_value) ", stream-> mode, 1);


      We have added the fd field to the result returned by the stream_get_meta_data () function, if it makes sense (for example, for zlib streams, the fd field will not be present). We also replaced the dup () call from the passed file descriptor with a simple check. Unfortunately, this code will not work without modifications under Windows, since the fcntl () call is POSIX-specific, so the full patch should contain additional code branches for other operating systems.

      A daemon with no restart capability

      First, let's write a small server that can accept requests in JSON format and give some kind of response. For example, it will return the number of elements in the array that came in the request.

      The daemon is listening on port 31337. The output should be something like this:

      $ telnet localhost 31337 Trying 127.0.0.1 ... Connected to localhost. Escape character is "^]". ("hash": 1) # user input "Request had 1 keys" ("hash": 1, "cnt": 2) # user input "Request had 2 keys"

      We will use stream_socket_server () to start listening on the port and stream_select () to determine which descriptors are ready to read / write.

      Simplest implementation code (Simple.php)

      stream) * / private $ streams =; / ** @var string (client_id => read buffer) * / private $ read_buf =; / ** @var string (client_id => write buffer) * / private $ write_buf =; / ** @var resource (client_id => stream from which to read) * / private $ read =; / ** @var resource (client_id => stream where to write) * / private $ write =; / ** @var int Total connection count * / private $ conn_count = 0; public function run () ($ this-> listen (); echo "Entering main loop \ n"; $ this-> mainLoop ();) protected function listen () ($ port = self :: PORT; $ ip_port = " 0.0.0.0:$port "; $ address =" tcp: // $ ip_port "; $ server = stream_socket_server ($ address, $ errno, $ errstr, STREAM_SERVER_BIND | STREAM_SERVER_LISTEN); if (! $ Server) (fwrite (STDERR, "stream_socket_server failed: $ errno $ errstr \ n"); exit (1);) $ this-> read = $ server; echo "Listening on $ address \ n";) public function response ($ stream_id, $ response) ( $ json_resp = json_encode ($ response); echo "stream $ stream_id". $ json_resp. "\ n"; $ this-> write ($ stream_id, $ json_resp. "\ n");) public function write ($ stream_id, $ buf) ($ this-> write_buf [$ stream_id]. = $ buf; if (! isset ($ this-> write [$ stream_id])) ($ this-> write [$ stream_id] = $ this-> streams [$ stream_id];)) public function accept ($ server) (echo "Accepting new connection \ n"; $ client = stream_socket_accept ($ server, 1, $ peername); $ stream_id = ($ this-> conn_count + +); if (! $ client) (fwrite (STDERR, "Accept failed \ n"); return;) stream_set_read_buffer ($ client, 0); stream_set_write_buffer ($ client, 0); stream_set_blocking ($ client, 0); stream_set_timeout ($ client, 1); $ this-> read_buf [$ stream_id] = ""; $ this-> write_buf [$ stream_id] = ""; $ this-> read [$ stream_id] = $ this-> streams [$ stream_id] = $ client; echo "Connected stream $ stream_id: $ peername \ n"; ) private function disconnect ($ stream_id) (echo "Disconnect stream $ stream_id \ n"; unset ($ this-> read_buf [$ stream_id], $ this-> write_buf [$ stream_id]); unset ($ this-> streams [ $ stream_id]); unset ($ this-> write [$ stream_id], $ this-> read [$ stream_id]);) private function handleRead ($ stream_id) ($ buf = fread ($ this-> streams [$ stream_id ], 8192); if ($ buf === false || $ buf === "") (echo "got EOF from stream $ stream_id \ n"; if (empty ($ this-> write_buf [$ stream_id]) ) ($ this-> disconnect ($ stream_id);) else (unset ($ this-> read [$ stream_id]);) return;) $ this-> read_buf [$ stream_id]. = $ buf; $ this-> processJSONRequests ($ stream_id);) private function processJSONRequests ($ stream_id) (if (! strpos ($ this-> read_buf [$ stream_id], "\ n")) return; $ requests = explode ("\ n", $ this -> read_buf [$ stream_id]); $ this-> read_buf [$ stream_id] = array_pop ($ requests); foreach ($ requests as $ req) ($ res = json_decode (rtrim ($ req), true); if ( $ res! == false) ($ this-> response ($ stream_id, "Request had". count ($ res). "keys");) else ($ this-> response ($ stream_id, "Invalid JSON");)) ) private function handleWrite ($ stream_id) (if (! isset ($ this-> write_buf [$ stream_id])) (return;) $ wrote = fwrite ($ this-> streams [$ stream_id], substr ($ this-> write_buf [$ stream_id], 0, 65536)); if ($ wrote === false) (fwrite (STDERR, "write failed into stream # $ stream_id \ n"); $ this-> disconnect ($ stream_id); return ;) if ($ wrote === strlen ($ this-> write_buf [$ stream_id])) ($ this-> write_buf [$ stream_id] = ""; unset ($ this-> write [$ stream_id]); if (empty ($ this-> read [$ stream_id])) ($ this-> disconnect ($ stream_id);)) else ($ this-> write_buf [$ stream_id] = substr ($ this-> write_buf [$ stream_id] , $ wrote);)) public function mainLoop () (while (true) ($ read = $ this-> read; $ write = $ this-> write; $ except = null; echo "Selecting for". count ($ read). "reads,". count ($ write). "writes \ n"; $ n = stream_select ($ read, $ write, $ except, NULL); if (! $ n) (fwrite (STDERR, "Could not stream_select () \ n");) if (count ($ read)) (echo "Can read from". count ($ read). "streams \ n" ;) if (count ($ write)) (echo "Can write to". count ($ write). "streams \ n";) if (isset ($ read)) ($ this-> accept ($ read); unset ($ read);) foreach ($ read as $ stream_id => $ _) ($ this-> handleRead ($ stream_id);) foreach ($ write as $ stream_id => $ _) ($ this-> handleWrite ( $ stream_id);)))) $ instance = new Simple (); $ instance-> run ();


      The code for this daemon is more than standard, but I would like to note one implementation detail: we store all read and write buffers with binding to specific connections and perform request processing right in the same place where we read the request. This is important because one of these requests can be restart, in which case it will not come to processing the next requests. However, since we have not read the requests yet, the next time stream_select () from the same descriptors will return the same result. Thus, we will not lose a single request if we restart directly from the command handler (except for the case when we are sent several commands at once to the same connection, and one of these commands will be restart).

      So how do you make it possible to restart the daemon?

      Daemon with restart and saving established connections

      Our simplest example did not know how to do anything useful, so let's still write the demon that was discussed at the very beginning. We want to receive something like the following (commands are sent to the daemon in the form "command_name [JSON-data]", the response is in the form of JSON):
      $ telnet localhost 31337 Trying 127.0.0.1 ... Connected to localhost. Escape character is "^]". # immediately ask the daemon to restart restart # the response is sent by the already restarted daemon "Restarted successfully" # run the test class run ("hash": 1, "params":, "class": "TestClass1") # started successfully ("error_text": "OK") # restart the daemon again (its child TestClass1 is still running) restart "Restarted successfully" # check the status of the job: still running check ("hash": 1) ("error_text": "Still running") # wait 5 seconds and check again: the TestClass1 class worked successfully check ("hash": 1) ("retcode": 0) # the daemon remembers all launches, so you need to free check ("hash": 1) ("retcode": 0) free ("hash": 1) ("error_text": "OK") restart "Restarted successfully" # I updated the code, so the second time we see a different response to restart restart ("error_text": "Restarted successfully") bye Connection closed by foreign host.

      The idea for a restart is simple: we will create a file with all the necessary information, and upon startup we will try to read it and restore open file descriptors.

      First, let's write the code to write to the restart file:

      Echo "Creating restart file ... \ n"; if (! $ res = $ this-> getFdRestartData ()) (fwrite (STDERR, "Could not get restart FD data, exiting, graceful restart is not supported \ n"); exit (0);) / * Close all extra file descriptors that we do not know of, including opendir () descriptor :) * / $ dh = opendir ("/ proc / self / fd"); $ fds =; while (false! == ($ file = readdir ($ dh))) (if ($ file === ".") continue; $ fds = $ file;) foreach ($ fds as $ fd) (if (! isset ($ this-> known_fds [$ fd])) (fclose (fopen ("php: // fd /". $ fd, "r +"));)) $ contents = serialize ($ res); if (file_put_contents (self :: RESTART_DIR. self :: RESTART_FILENAME, $ contents)! == strlen ($ contents)) (fwrite (STDERR, "Could not fully write restart file \ n"); unlink (self :: RESTART_DIR. self :: RESTART_FILENAME);)

      The code for getting an array of data (the getFdRestartData () function) is shown below:

      $ res =; foreach (self :: $ restart_fd_resources as $ prop) ($ res [$ prop] =; foreach ($ this -> $ prop as $ k => $ v) ($ meta = stream_get_meta_data ($ v); if (! isset ($ meta ["fd"])) (fwrite (STDERR, "No fd in stream metadata for resource $ v (key $ k in $ prop), got". var_export ($ meta, true). "\ n") ; return false;) $ res [$ prop] [$ k] = $ meta ["fd"]; $ this-> known_fds [$ meta ["fd"]] = true;)) foreach (self :: $ restart_fd_props as $ prop) ($ res [$ prop] = $ this -> $ prop;) return $ res;
      The code takes into account that we have 2 types of properties:

      1. Properties containing resources with connections: $ restart_fd_resources = ["read", "write", "streams"].
      2. Properties containing buffers and other connection information that can be "serialized" in their raw form: $ restart_fd_props = ["read_buf", "write_buf", "conn_count"].
      We also remember all the fd's saved in the restart file and close all the others (if any), because otherwise we might leak file descriptors.

      Next, we must load this file at the start and continue to use open descriptors, as if nothing happened :). The code for two functions (loading the restart file and loading information about file descriptors) is shown below:

      If (! File_exists (self :: RESTART_DIR. Self :: RESTART_FILENAME)) (return;) echo "Restart file found, trying to adopt it \ n"; $ contents = file_get_contents (self :: RESTART_DIR. self :: RESTART_FILENAME); unlink (self :: RESTART_DIR. self :: RESTART_FILENAME); if ($ contents === false) (fwrite (STDERR, "Could not read restart file \ n"); return;) $ res = unserialize ($ contents); if (! $ res) (fwrite (STDERR, "Could not unserialize restart file contents"); return;) foreach (self :: $ restart_props as $ prop) (if (! array_key_exists ($ prop, $ res)) (fwrite (STDERR, "No property $ prop in restart file \ n"); continue;) $ this -> $ prop = $ res [$ prop];) $ this-> loadFdRestartData ($ res);

      The loadFdRestartData () function to expand the file descriptor array back:

      $ fd_resources =; foreach (self :: $ restart_fd_resources as $ prop) (if (! isset ($ res [$ prop])) (fwrite (STDERR, "Property" $ prop "is not present in restart fd resources \ n"); continue; ) $ pp =; foreach ($ res [$ prop] as $ k => $ v) (if (isset ($ fd_resources [$ v])) ($ pp [$ k] = $ fd_resources [$ v];) else ($ fp = fopen ("php: // fd /". $ v, "r +"); if (! $ fp) (fwrite (STDERR, "Failed to open fd = $ v, exiting \ n"); exit (1);) stream_set_read_buffer ($ fp, 0); stream_set_write_buffer ($ fp, 0); stream_set_blocking ($ fp, 0); stream_set_timeout ($ fp, self :: CONN_TIMEOUT); $ fd_resources [$ v] = $ fp ; $ pp [$ k] = $ fp;)) $ this -> $ prop = $ pp;) foreach (self :: $ restart_fd_props as $ prop) (if (! isset ($ res [$ prop])) ( fwrite (STDERR, "Property" $ prop "is not present in restart fd properties \ n"); continue;) $ this -> $ prop = $ res [$ prop];)
      We re-set the read_buffer and write_buffer values ​​for open file descriptors and set the timeouts. Oddly enough, after these manipulations PHP quite calmly makes accept () on these file descriptors and continues to read / write to them normally, even though it does not know that these are sockets.

      In the end, we have to write logic for starting and monitoring the execution status of workers. Since this is not relevant to the topic of the article, the full implementation of the daemon has been posted on the github repository, the link to which is given below.

      Conclusion

      So, this article described the implementation of a daemon that communicates using the JSON protocol and is able to run arbitrary classes in separate processes with monitoring the process of their execution. To run individual classes, the model is used fork () per request, therefore, to process the request, you do not need to restart the interpreter and load the framework, while it becomes possible to use the opcode cache in the CLI. Since the daemon needs to be restarted every time the code is updated, it is necessary to provide a mechanism for smooth restarting of this daemon (in our company, the code is sometimes updated every few minutes, in the form of "hotfixes").

      The restart occurs by executing the execve () system call, as a result of which all children remain attached to the parent (since the PID of the process does not change during execve ()). Also, all open file descriptors are saved, which allows you to continue to process requests from users in already open connections. All network buffers, information about running children and about open descriptors are saved in a separate restart file, which is read by a new instance of the daemon, after which work continues in the standard event loop.

      The complete implementation code can be seen on GitHub at the following URL.