Meny
Är gratis
registrering
Hem  /  / Oåterkallelig framgång php. Ett enkelt exempel med PHP och AJAX

Oåterkallelig framgång php. Ett enkelt exempel med PHP och AJAX

Hälsningar, kära vän!

"Vad är framgång i livet för dig ???"

Snälla, tänk på det, stanna upp en minut.

Okej, låt mig hjälpa dig nu. Vad som inte är en framgång skrev jag i förra maillistan. Låt oss förkasta dessa begrepp direkt.

Framgång är sinnesfrid.
Framgång är att vara lycklig.
Framgång är förverkligandet av sig själv och avslöjandet av sin potential.
Framgång är tillfredsställelse i livet.
Framgång är att göra det du älskar, vilket tänder dig och du kan göra det dygnet runt.
Framgång är att ge dig själv till andra och göra världen till en bättre plats och lyckligare andra människor.
.

Framgång är oupplösligt kopplad till sinnestillstånd. Vår själ kom till denna värld för att njuta och förverkliga sig själv, och vi (vårt sinne, vår kropp, vårt medvetande) måste stödja den i detta. När vår själ skapar och förverkligar sig själv känner vi oss lyckliga. När vi känner och ser att skapandet av vår själ och det vi gör är till stor nytta för andra människor, känner vi lycka. Detta är vad som kallas framgång. Framgång är uppfyllelsen av livet.

Varje förverkligande av själens talanger är endast möjlig tack vare andra människor... Själen skapar inte för sig själv. Hon skapar åt andra – för att hjälpa dem och göra andras liv uppfyllda och ge dem en bit av sin lycka. En lycklig person överför en del av sin lycka till andra, en olycklig person överför sin olycka till andra. Undvik olyckliga människor!

Om plötsligt i det ögonblick alla människor försvinner, blir självförverkligande omöjligt - vad är poängen med att skriva böcker, eftersom ingen kommer att läsa dem, vad är poängen med att skapa nya modeller av kläder, eftersom ingen kommer att bära dem, vad är poängen med att bygga nya hus där ingen kommer att bo?

Uppenbarligen är det inte vettigt.

Här dyker det upp framgångens dubbla natur: själen skapar och förverkligar sig själv, och hjälper även andra människor att bli lyckligare.
Mest exakt definition framgång som jag skulle kunna ge skulle låta så här: framgång är förverkligandet av dina sanna talanger, som gör vår värld bättre, mer perfekt och människor lyckligare.

Jag vill att du djupt inser det människor som bara lever för sig själva och samlar rikedomar endast för sig själva är olyckliga... De samlar in denna rikedom för att fylla det andliga tomrummet som har bildats som ett resultat av ett meningslöst liv. Men detta tomrum kan bara fyllas med kärlek, vilket ger värde till andra människor. Själen är glad när den ger sig själv utan överskott för att göra denna värld till en bättre plats. Och vad är poängen med alla de rikedomar som en person har samlat på sig när han går bort, eftersom vi inte är hållbara. Själen kommer för att skapa värde, förverkliga sig själv och återvänder sedan "hem". Om hon inte skapar detta värde, utan gör något annat, mår hon dåligt. Hon känner att hon har kommit till den här världen och inte gör som hon vill. Och anledningen till detta är vårt sinne - det är förblindat av "framgång" i den allmänna förståelsen av detta ord. Han jagar efter det illusoriska, och när han uppnår detta, om alls, inser han meningslösheten i det han har uppnått.

Och vad är framgång i allmän förståelse?
- rikedom (pengar, materiella saker)
- ära, makt, popularitet
- status

Men se, allt kommer från egot. En person vill känna sin egen betydelse, men han förstår inte att rikedom, berömmelse, status är en illusion. De är som havsvatten, som oavsett hur mycket du dricker kommer du aldrig att stilla din törst. Därför människor hela livet och jagar efter dem. De tror att jag kommer att tjäna så mycket pengar och jag kommer att vara glad, att jag kommer att gå till en inkomstnivå på 100 000 $ om året och sedan kommer jag att vara glad, när jag går upp på scenen och sjunger var lycklig, jag ska gifta mig, jag ska skaffa barn ... du kan kolla upp det, men jag kan med 100% säkerhet säga att du inte kommer att bli lycklig. Dessutom kommer din nivå av lycka bli ännu lägre. Du går bort från ditt kall och inser detta blir själen ännu mer olycklig. Ju mer rikedom, berömmelse, status du får, desto mer kontroll över livet tar sinnet och desto längre skjuts själens roll tillbaka. Men sann lycka kommer från själen!!!

Framgång är harmoni mellan själ och sinne. Förnuftets roll är att att hjälpa själ att självförverkliga. Vi prioriterar fel. Vi sätter den kortlivade kroppen och de materiella sakerna i första hand, och vi sätter den odödliga själen och den outtömliga rikedomen i sista hand. Bibeln säger, "samla rikedom i himlen, inte på jorden." Vår kropp är ett fordon för själen... Själen är förbunden med det högre sinnet och bara den kan förstå vad som behövs för denna värld. Universum uppmuntrar människor som går sin egen väg... Din väg är den minst energikrävande, och i vår värld flyter allt längs minsta motståndets väg. Jag säger alltid att framgång är ett normalt förlopp. Misslyckande är en avvikelse från normen. Om du nu inte är så framgångsrik som du vill, då gör du inte det du är ämnad att göra. Själ och sinne är motstridiga. Och ju mer denna oenighet är, desto mer olycklig är personen.

Men tro inte att jag säger att en person inte behöver materiella saker. Mycket till och med nödvändigt. Och här är varför: när en person inte har några pengar, tvingas han gå till jobbet och ägna sig åt någon form av "dumhet". En person spenderar 10 timmar om dagen för att tjäna pengar, men genom att göra detta inser han inte sig själv. Kocken är personen som förverkligar sig själv på bekostnad av dig. (Jag säger hur det går till i de flesta fall. De flesta hatar sina jobb, men de jobbar för att de behöver pengar för att överleva).

Materiella ting skapar tröst för själen. Materiella ting utrustar denna värld för själen. Det är mycket trevligare för själen att skapa mästerverk på platser som inspirerar den. Det är mycket bättre att måla en bild i ett hus vid havet än i en "avloppspool". Själen behöver frid och tröst för att kunna skapa. Men vilken fred kan det bli om familjen inte har tillräckligt med pengar och varje dag bråkar mannen och hustrun om detta.

Själen behöver tid att uttrycka sig. Först efter att en tid har gått kan värdet som skapas av själen säljas och säljas hundratals, eller till och med tusentals gånger dyrare än en person får på jobbet. Men det tar tid att skapa sådana värden. Personligen tog det mig 5 månader att komma upp med en mager inkomst. Efter 8 månader började min sida generera inkomster som en fattig familj redan kunde leva på. Och bara 17 månader senare började min sida generera inkomster, som redan kommer att ersätta inkomster från ett mycket högbetalt jobb.

Det tog 17 månader att ersätta jobbet. Men nu är jag ledig! Jag gör det jag älskar och det här är bara början. Det finns inga gränser för mina drömmar – och därför finns det inga gränser för mig. När du gör ditt företag begränsas din inkomst bara av din fantasi och inget mer. Vem på jobbet tjänar 1 000 000 dollar per år? Ja, det kan finnas en. Men gör din egen grej, inte ens detta är ett kapell.
Materialet är viktigt, men bara för att tillfredsställa behoven att leva.

Jag ska vara ärlig: inte får inkomst är det svårare att skapa och skapa mästerverk... Sinnet säger hela tiden: "det du gör är bra, men vad ska vi leva för?" Och denna fråga distraherar konstant och starkt från kreativiteten. Han tar bort vår lycka. För att stänga av denna dialog måste din favoritsysselsättning ge pengar. Självklart börjar sinnet då ställa andra frågor, men hur mer pengar ger det du älskar, desto mindre smärtsamma och distraherande blir dessa problem.

Ofta arbetar folk på jobbet, tjänar pengar, men har fortfarande en hobby. Vad är en hobby?
En hobby är en hobby som inte genererar inkomst. Men varför inte förvandla en hobby till ett jobb? De lyckligaste människorna är de vars hobby är arbete.... De gör oavbrutet det de älskar.
Allt jag pratar om, om arbete, om pengar, vill jag förmedla till dig två viktiga tankar: 1) Själ och sinne måste vara i harmoni
2) Det immateriella ska alltid komma först

Fokus ska bara ligga på det immateriella! Material som ska bifogas som en konsekvens... Här är de rätta prioriteringarna i livet:
lycka -> hälsa -> rikedom Och många människor lever enligt schemat
rikedom-> hälsa-> lycka
Och ännu värre, det finns människor som lever enligt mönstret
rikedom-> rikedom-> rikedom

Inte konstigt att de inte är nöjda. Dessa människor har miljoner, men de har inga vänner, de har familjeproblem. De har problem i relationer med människor. För att de tror att alla människor som omger dem är med dem bara på grund av deras pengar och inget annat. Jag vet inte om dig, men jag skulle inte vilja ha sådan lycka. När prioriteringarna i livet är rätt inställda uppstår rikedom som ett resultat. Det är ingen idé att fokusera på det. Höga nivåer av lycka och hälsa leder oundvikligen till höga inkomstnivåer.

Materiella ting och vår rikedom kan bara tjäna som ett tillägg till vår lycka. De kan inte fungera som en grund. Vad är grunden har vi redan diskuterat med dig ovan.

Uppsättningen nyckel-/värdepar som anpassar begäran AJAX. Alla parametrar är valfria... Det är tillåtet men rekommenderas inte att ställa in ett standardvärde för någon parameter med metoden $ .ajaxSetup ().
Metod $ .ajax () stöder följande parametrar:

    accepterar(standard: beror på data typ).

    Typ: PlainObject.
    Uppsättningen nyckel-/värdepar som skickas till Acceptera begäran header. Denna rubrik talar om för servern vilken typ av svar begäran kommer att acceptera som svar. Observera att värdet på parametern som anges i data typ(datatypen som vi förväntar oss från servern) matchas med den som anges i parametern. Dessutom, för korrekt behandling av svaret från servern, är det nödvändigt i parametern omvandlare ange en funktion som returnerar det konverterade svarsvärdet. Till exempel: $ .ajax (( accepterar: (mycustomtype: " applikation / x-some-custom-type" } , // ange hur svaret ska behandlas omvandlare: ("text mycustomtype": funktion ( resultat) { // returnera det transformerade svarsvärdet returnera nytt resultat; )), // Förväntad datatyp ("mycustomtype") data typ: "mycustomtype"));

    asynkron(standard: sant).

    Typ: Boolean.
    Som standard skickas alla förfrågningar asynkront, om du behöver organisera synkrona förfrågningar, ställ sedan in denna parameter på false. Observera att förfrågningar över flera domäner och element, parameter data typ som betyder något "jsonp" stöder inte synkrona förfrågningar. Observera att med synkrona förfrågningar kan du tillfälligt blockera webbläsaren genom att inaktivera alla åtgärder medan begäran är aktiv.

    innanSkicka... Typ: Funktion (jqXHR jqXHR, PlainObject inställningar).
    Återuppringningsfunktion som kommer att anropas innan AJAX-förfrågan görs. Den här funktionen låter dig modifiera jqXHR-objektet (i jQuery 1.4.x XMLHTTPRequest-objektet) innan det skickas. jqXHR-objektet är ett tillägg som utökar XMLHttpRequest-objektet, objektet innehåller många egenskaper och metoder som gör att du kan få mer fullständig information om serverns svar, samt objektet innehåller Promise-metoder. Om funktionen innanSkicka returnerar false, då kommer AJAX-begäran att avbrytas. Från version jQuery 1.5 fungera innanSkicka kommer att anropas oavsett typ av begäran.

    cache(standard: sant, för data typ "manus" och "jsonp" falsk).

    Typ: Boolean.
    Om det är inställt på false kommer detta att göra att de begärda sidorna inte cachelagras av webbläsaren. Observera att false bara fungerar korrekt med HUVUD och SKAFFA SIG förfrågningar.

    komplett.

    Typ: Funktion (jqXHR jqXHR, Sträng textStatus).
    En funktion som anropas när begäran avslutas (funktionen exekveras efter AJAX-händelser "Framgång" eller "fel"). Två parametrar skickas till funktionen: jqXHR(i jQuery 1.4.x-objekt XMLHTTPRequest) och en rad som motsvarar förfrågans status ( "Framgång", "ej modifierad", "inget innehåll", "fel", "Paus", "avbryta", eller "parsererror"). Sedan jQuery 1.5, parametern komplett kan ta en rad funktioner som kommer att anropas i tur och ordning.

    innehåll.

    Typ: PlainObject.
    Ett objekt som består av sträng-/reguljära uttryckspar som definierar hur jQuery ska analysera (parsera) svaret beroende på innehållstypen. Lades till i jQuery 1.5.

    innehållstyp(standard: "applikation / x-www-form-urlenkodad; teckenuppsättning = UTF-8").

    Typ: Boolean eller String.
    Bestämmer vilken typ av innehåll som anges i begäran när data skickas till servern. Sedan jQuery 1.6 är det tillåtet att ange värdet false, i vilket fall jQuery inte passerar fältet i rubriken Innehållstyp alls.

    sammanhang.

    Typ: PlainObject.
    När AJAX-återuppringningar exekveras är deras exekveringskontext fönsterobjektet. Parameter sammanhang låter dig ställa in exekveringskontexten för en funktion på ett sådant sätt att $ (detta) kommer att referera till ett specifikt DOM-element eller objekt. Till exempel: $ .ajax (( url: "test.html", sammanhang: $ (". myClass"), // nytt sammanhang för funktionsexekvering Framgång: funktion () ( // om begäran lyckas, anropa funktionen$ (detta) .html ("Allt är OK"); // lägg till textinnehåll till elementet med class.myClass } } );

    omvandlare

    Ursprungliga värden:
    ("* text": window.String, // vilken typ som helst till text"text html": sant, // text i html "text json": jQuery.parseJSON, // text i JSON "text xml": jQuery.parseXML // text i XML) Skriv: PlainObject.
    Ett objekt som innehåller datatypen som ska konverteras och hur den konverteras. Värdet för varje transformator är en funktion som returnerar det transformerade svarsvärdet. Lades till i jQuery 1.5.

    crossDomain(standard: falskt för förfrågningar inom samma domän, sant för förfrågningar över flera domäner).

    Typ: Boolean.
    Om du vill göra en begäran över flera domäner medan du är på samma domän (till exempel en jsonp-begäran), ställ in den här parametern till true. Detta gör det till exempel möjligt att omdirigera begäran till en annan domän från din server. Lades till i jQuery 1.5.

    Typ: PlainObject eller String eller Array.
    Data som ska skickas till servern. Om de inte är en sträng konverteras de till en frågesträng. För SKAFFA SIG frågesträngen kommer att läggas till URL:en. För att förhindra automatisk bearbetning kan du använda parametern processData med värdet falskt. Om data överförs som en del av ett objekt måste det bestå av nyckel-/värdepar. Om värdet är en array, serialiserar jQuery flera värden med samma nyckel (beroende på parameterns värde traditionell som tillåter oss att använda den traditionella serialiseringstypen baserad på $ .param-metoden).

    datafilter.

    Typ: Funktion (String data, Sträng typ) => Vad som helst.
    Funktionen anropas efter framgångsrik exekvering av AJAX-begäran och låter dig bearbeta "rå" data som tas emot från serversvaret. Uppgifterna ska returneras omedelbart efter behandlingen. Funktionen tar två argument: data- data som tas emot från servern som en sträng och typ- typen av denna data (parametervärde data typ).

    data typ(standard: xml, json, manus, eller html).

    Typ: Sträng.
    Definierar typen av data som du förväntar dig att ta emot från servern. Om ingen datatyp anges, kommer jQuery att försöka bestämma den baserat på MIME-typen från svaret ( XML sorts MIMA kommer att resultera i XML från och med jQuery 1.4 json kommer att ge ett objekt JavaScript, manus kommer att köra skriptet och allt annat kommer att returneras som en sträng).

    Grundläggande typer (resultatet skickas som det första argumentet till återuppringningsfunktionen Framgång):

    • "xml"- returnerar XML ett dokument som kan renderas med jQuery.
    • "html"- returnerar Html som vanlig text, taggar

      Det enklaste sättet att arbeta med AJAXÄr att koppla ihop ramverket jQuery, vilket jag faktiskt gjorde. jQuery ger oss en lättförståelig och lättanvänd syntax för sändning AJAX förfrågningar, varför inte dra nytta av detta?

      Js skript skapande

      Syntaxen för filen validate.js är

      $ (dokument) .ready (function () (var email = ""; $ ("# email"). keyup (function () (var value = $ (detta) .val (); $ .ajax ((typ: "POST", url: "email.php", data: "email =" + värde, framgång: funktion (msg) (if (msg == "giltigt") ($ ("# meddelande"). Html (" Denna e-post kan användas.Den här e-mailadressen är redan tagen.");))));)); $ (" # skicka "). klicka (funktion () (if (e-post ==" ") (varning (" Vänligen, lägg data till all e-post ");) else ( $ .ajax ((typ: "POST", url: "email.php", data: "add_email =" + email, success: function (msg) ($ ("# meddelande"). html (msg);)) ;)))))));

      Php-hanterare

      Detta skript kommer att ta emot POSTA begäran från klienten, bearbeta den och returnera resultatet. AJAX läser av resultatet och fattar ett beslut utifrån det.
      Syntaxen för filen email.php är

      $ connection = mysqli_connect ("localhost", "e-post", "e-post", "e-post"); if (isset ($ _ POST ["email"]) && $ _POST ["email"]! = "") ($ email = $ _POST ["email"]; $ email = mysqli_real_escape_string ($ anslutning, $ email); if (! filter_var ($ email, FILTER_VALIDATE_EMAIL)) (eko "ogiltig";) else ($ sql = "SELECT id FROM email WHERE email =" $ email ""; $ resultat = mysqli_query ($ anslutning, $ sql); if ( mysqli_num_rows ($ resultat) == 1) (eko "ogiltig";) else (eko "giltig";))) if (isset ($ _ POST ["add_email"]) && $ _POST ["add_email"]! = "" ) ($ email = mysqli_real_escape_string ($ anslutning, $ _ POST ["add_email"]); $ sql = "INSERT I e-post (e-post) VÄRDEN (" $ email ")"; if (mysqli_query ($ anslutning, $ sql) )) ( eko Framgång";) annat (eko" Fel"; } }

      I vårt php-skript är den vanligaste koden som behandlar en postförfrågan och skriver ut lite text på sidan. Som ett resultat AJAX skickar en förfrågan php-skript, skriptet bearbetar det och producerar resultatet, AJAX läser resultatet och ändrar sidan i realtid.

      AJAX skickar POST-begäran till skriptet genom denna kodbit:

      $ .ajax ((typ: "POST", url: "email.php", data: "email =" + värde, framgång: funktion (msg) (if (msg == "giltigt") ($ ("# meddelande ") .html (" Denna e-post kan användas."); email = värde;) else ($ (" # meddelande "). html (" Den här e-mailadressen är redan tagen."); } } });

      typ - Typen av begäran, POST eller GET. I vårt fall, POST;
      url - adressen till skriptet som begäran skickas till;
      data - data som överförs i begäran;
      framgång - vad man ska göra som ett resultat av framgångsrikt genomförande av begäran. I vårt fall heter funktionen;

      I själva skriptet görs en kontroll av förekomsten av e-post i databasen varje gång ett tecken skrivs in i e-postfältet. I skriptet, $ ("# e-post"). Keyup (funktion () ()); som letar efter en knapptryckning i fältet med id = "e-post".
      Som du kan se är koden ganska enkel och kräver inte särskilt stora färdigheter för att förstå, allt är knutet till att hantera keyup ()-händelser - trycka på en tangent, klicka () - klicka på ett element. Följd av AJAX begäran och svar från manuset. Med php och ajax kan du alltså få nästan oändliga möjligheter att skapa interaktiva sidor.
      Den här koden gör inte anspråk på att vara av hög kvalitet, men om du utvecklar den, lägger till rätt valideringar på klient- och servernivå, anger css, så kan du helt enkelt använda den i dina projekt.
      Om du har några frågor, tveka inte att skriva kommentarer.
      Ha en bra dag så ses vi snart 🙂

      Visum: Blaue Karte EU

      Vid tidpunkten för inlämning av dokument 29 år gammal

      Från Astrakhan

      Ambassadstad: Moskva

      Universitet, specialitet: Astrakhan State Technical University, Complex support informationssäkerhet automatiserade system

      Språk: Engelska mellanliggande

      Hur allt började:

      Viljan att flytta någonstans har funnits länge. Däremot övervägdes främst varma länder med havet. Två gånger undersökte de jorden på allvar i syfte att flytta till Montenegro eller Bulgarien. Som ett resultat ändrade de sig i sista stund av en eller annan anledning. Senast var i september 2014 efter seriösa förberedelser inför försäljningen av bilen.

      I oktober såg jag av misstag en annons om sökandet efter programmerare med en flytt till Tyskland. Då hade jag ingen aning om att det blå kortet fanns och ansåg att Tyskland var ett land med en otroligt tuff migrationspolitik gentemot icke-EU-medborgare.

      Med en viss skepsis och misstro skrev jag till Skype. På andra sidan skärmen svarade en rekryterare (Alina), som sysslar med urvalet av IT-personal, med efterföljande omplacering till Tyskland. Vid tidpunkten för vår första kommunikation skedde en rekrytering av programmerare till en stor webbutik med huvudkontor i Berlin. Jag skickade in mitt CV och väntade.

      Efter ett tag sa Alina att hennes kollega från Tyskland skulle prata med mig för att bedöma språknivån och adekvatheten. Intervjun är snarare bara ett samtal med två logiska uppgifter, den varade i 30 minuter på Skype. Sedan blev jag tillsagd att vänta. Någon vecka senare var den första tekniska intervjun inplanerad. Den tekniska intervjun gjordes också via Skype med en av företagets utvecklare. Enligt mig gick det ganska bra, men en vecka senare fick jag beskedet att jag inte var lämplig. Förresten, inte en enda kandidat från Alina klarade av vissa skäl.

      Hur det hela blev:

      Lite upprörd, men livet går vidare. Och några dagar senare sa Alina att de hade en ny kund från Stuttgart som letade efter utvecklare, och en intervju var inbokad för mig. Den första delen av intervjun delas med chefen för IT- och HR-avdelningarna. Ett allmänt samtal om erfarenhet, mig själv och företaget, mycket skratt och skämt på båda sidor. Tydligen föll min humor i min smak, så några dagar senare var jag planerad till en teknisk intervju med en potentiell linjechef. Den här delen av intervjun överraskade mig lite, för, som en av kandidaterna uttryckte det senare, var det som "ett samtal mellan två programmerare över en öl". Senare samma kväll fick jag en inbjudan till en personlig intervju på kontoret.

      På den tiden hade jag inget öppet Schengenvisum. De nödvändiga dokumenten samlades omedelbart in. På det tyska visumansökningscentret i Moskva ansökte jag om brådskande visum och redan nästa dag tog jag mitt pass med visum. Jag sökte affärsvisum på inbjudan som skickades till mig från Esslingen är bara ett brev där jag är inbjuden för kommunikation och där det tydligt framgår att alla ekonomiska frågor med flyg, transfer, måltider och boende sköts av företaget.

      Personlig kommunikation på kontoret skedde med företagets tre huvudsakliga IT-ledare. Den första delen är, återigen, bara kommunikation om erfarenhet, färdigheter och allmän förståelse för vissa frågor. Den andra är vid datorn. Ärligt talat, väldigt, väldigt enkla uppgifter på nivån "junior med testerfarenhet" :). Uppdragen gjordes. Därefter lunch och omgående ett erbjudande i form av två exemplar av arbetskontrakt (position Senior PHP-utvecklare) undertecknat av företaget. Jag tog mig lite betänketid och sa att jag skulle svara inom en vecka.

      Beslutet togs och jag började förbereda mig på att ansöka om visum.

      Hur vi flyttade:

      Företaget betalade flyget för mig och min familj (hustru och dotter 2,5 år), hyrde en lägenhet åt oss under de första tre månaderna (i mitt fall en idealisk plats med utsikt över det centrala torget på Marktplatz) och anvisade en person till hjälp för första gången. Detta är inte en omplaceringsagent i ren form, men vi löste alla nya problem genom henne. Jag var den första anställde utanför EU i företaget, så många frågor ställdes till mig. Nu, förutom jag, jobbar en annan kille från Kiev i företaget (han flög in en månad efter mig) och en utvecklare från Odessa förbereder sig för att flytta. Alla var också anställda inte utan hjälp av Alina.

      Här vill jag säga att jag är mycket tacksam mot Alina som löste alla frågor som jag hade i anställningsprocessen. Jag hade mycket tur att det i alla stadier av anställning och efterföljande anpassning fanns en person som var redo att hjälpa och lösa det nödvändiga problemet.

      Först flög jag in ensam, två veckor senare kom min familj. Vid ankomsten träffas ingen, de första dagarna bodde jag på hotell i väntan på att min lägenhet skulle utrymmas. De hämtade mig från hotellet och tog mig till platsen 🙂

      De tog det nödvändiga minimumet från saker och ting.

      Med ABH gick allt väldigt snabbt. Alla sådana frågor löstes tillsammans med en anställd i företaget. ABH tillsatte mandatperioden tillräckligt tidigt efter ankomst, vi lämnade in handlingar och tre veckor senare fick vi våra eAT-kort.

      Hur vi slog oss ner:

      det här ögonblicket vi bor i Esslingen, en otroligt vacker och ren stad bara 15 minuter från Stuttgart. Vi upplever ännu inte något obehag på grund av att vi inte kan språket, i de flesta fall kan vi förklara oss på engelska eller, i extrema fall, med gester. Det enda problemet som finns just nu är att hyra en lägenhet. Det finns väldigt få erbjudanden och efterfrågan är otroligt stor. Bostadssituationen i Stuttgart är lite lättare, men jag skulle vilja stanna i Esslingen.

      Kort sammanfattning med ungefärliga datum:

      Mitten av oktober 2014- såg en annons om sökandet efter programmerare

      Slutet av oktober - mitten av november - intervjuer med det första företaget

      Mitten av november - slutet av november - Intervjuer med mitt nuvarande företag, få erbjudande om en intervju ansikte mot ansikte

      20 januari - 1 februari 2015 g.- ansöka om ett nationellt visum, skaffa pass med visum

      ). Molnet är designat för att köra olika PHP-skript enligt ett schema eller via ett API. Vanligtvis bearbetar dessa skript köer och belastningen "sprids" över cirka 100 servrar. Tidigare har vi fokuserat på hur kontrolllogiken implementeras, som ansvarar för att fördela belastningen jämnt över ett sådant antal servrar och generera uppgifter enligt ett schema. Men utöver detta behövde vi skriva en demon som skulle kunna köra våra PHP-skript i CLI och övervaka statusen för deras exekvering.

      Det skrevs ursprungligen i C, som alla andra demoner i vårt företag. Vi stod dock inför det faktum att en betydande del av processortiden (cirka 10%) slösades bort, i själva verket förgäves: detta är att starta tolken och ladda "kärnan" i vårt ramverk. Därför, för att kunna initiera tolken och vårt ramverk endast en gång, beslutades det att skriva om demonen i PHP. Vi döpte den till Php sten syd (i analogi med Phproxyd - PHP Proxy Daemon, C-demonen som vi hade tidigare). Den accepterar förfrågningar om att starta individuella klasser och delar () för varje begäran, och vet också hur man rapporterar exekveringsstatusen för var och en av lanseringarna. Denna arkitektur liknar på många sätt Apache-webbservermodellen, när all initiering görs en gång i "guiden" och "barnen" redan hanterar förfrågan. Som en extra bonus får vi möjligheten att aktivera opcode-cachen i CLI, vilket kommer att fungera korrekt eftersom alla barn ärver samma delade minnesområde som masterprocessen. För att minska förseningarna i behandlingen av en startförfrågan kan du forka () i förväg (prefork-modell), men i vårt fall är fork () fördröjningar cirka 1 ms, vilket är bra för oss.

      Men eftersom vi uppdaterar koden ganska ofta, måste denna demon också startas om ofta, annars kan koden som laddas in i den bli föråldrad. Eftersom varje omstart skulle åtföljas av många fel i formuläret anslutningen återställd av peer, inklusive denials of service för slutanvändare (demonen är användbar inte bara för molnet, utan också för en del av vår webbplats), bestämde vi oss för att leta efter sätt att starta om demonen utan att förlora etablerade förbindelser... Det finns en populär teknik som används för att göra graciös omladdning för demoner: en fork-exec görs och en deskriptor från listen-socket skickas till barnet. Därmed är nya anslutningar redan accepterade. ny version demon, och de gamla är "modifierade" med den gamla versionen.

      I den här artikeln kommer vi att titta på ett mer komplicerat alternativ. graciös omladdning: gamla anslutningar kommer att fortsätta att behandlas av den nya versionen av demonen, vilket är viktigt i vårt fall, för annars kommer den att köra den gamla koden.

      Teori

      Låt oss tänka först: är det möjligt vad vi vill få? Och i så fall, hur kan detta uppnås?

      Eftersom demonen körs under Linux, som är POSIX-kompatibelt, är följande alternativ tillgängliga för oss:

      1. Alla öppna filer och sockets är nummer som motsvarar det öppna deskriptornumret. Standardinmatning, utdata och felström har deskriptorerna 0, 1 respektive 2.
      2. Inga signifikanta skillnader mellan öppna fil, socket och pipe är det inte (till exempel kan du arbeta med sockets med både läs/skriv och sendto/recvfrom systemanrop).
      3. När systemanropet fork () exekveras, ärvs alla öppna deskriptorer, vilket bevarar deras nummer och läs-/skrivpositioner (i filer).
      4. När execve () systemanropet körs, ärvs också alla öppna deskriptorer, och dessutom bevaras de. PID för processen och därför anknytning till sina barn.
      5. Listan över öppna processbeskrivningar är tillgänglig från katalogen / dev / fd, som på Linux är en symbollänk till / proc / self / fd.
      Därför har vi all anledning att tro att vår uppgift är genomförbar och utan större ansträngning. Så låt oss börja.

      PHP patchar

      Tyvärr finns det en liten detalj som komplicerar vårt arbete: i PHP finns det inget sätt att få filbeskrivningsnumret för strömmar och öppna filbeskrivningen efter nummer (istället öppnas en kopia av filbeskrivningen, vilket inte är lämpligt för vår demon, eftersom vi övervakar öppna deskriptorer mycket noggrant för att inte skapa läckor under omstart och när underordnade processer startas).

      Först kommer vi att göra ett par små patchar till PHP-koden för att lägga till möjligheten att hämta fd från en stream och göra det så att fopen (php: // fd / ) öppnade inte en kopia av handtaget (den andra ändringen är inkompatibel med det nuvarande PHP-beteendet, så du kan lägga till en ny "adress" istället, till exempel php: // fdraw / ):

      Patchkod

      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_wrapper.f c @@ -24,6 +24,7 @@ #if HAVE_UNISTD_H #inkludera #endif + # inkluderar #inkludera "php.h" #inkludera "php_globals.h" @@ -296.11 +297.11 @@ php_stream * php_stream_url_wrap_php (php_stream_wrapper * wrapper, char * sökväg, ch "Filbeskrivningarna måste vara mindre än %-negativa tal " , dtablesize); returnera NULL; ) - - fd = dup (fildes_ori); - if (fd == -1) (+ + fd = fildes_ori; + if (fcntl (fildes_ori, F_GETFD) == -1) (php_stream_wrapper_log_error (wrapper, alternativ TSRMLS_CC, - "Fel vid dupning av fildeskriptor% ld; möjligen gör det det inte "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 @ @ #inkludera " ext / standard / flock_compat.h" #inkludera "ext / standard / fil.h" #inkludera "ext / standard / php_filestat.h" + # include "ext / standard / php_fopen_wrappers.h" #inkludera "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_GSZEND_NUM_parameters () TSRMLS_CC, "r", & arg1) == FAILURE) (retur; @@ -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 (returvärde, "strömtyp", (char *) ström-> ops-> etikett, 1); + if (FRAMGÅNG == php_stream_cast (ström, PHP_STREAM_AS_FD_FOR_SELECT | PHP_STREAM_CAST_INTERNAL, (void *) & tmp_fd, 1) && tmp_fd! = -1) (+ add_assoc_long (return_value), "tmpd_value" 1);


      Vi har lagt till fd-fältet till resultatet som returneras av stream_get_meta_data ()-funktionen, om det är vettigt (till exempel för zlib-strömmar kommer fd-fältet inte att finnas). Vi ersatte också dup ()-anropet från den godkända filbeskrivningen med en enkel kontroll. Tyvärr kommer den här koden inte att fungera utan ändringar under Windows, eftersom fcntl ()-anropet är POSIX-specifikt, så den fullständiga patchen bör innehålla ytterligare kodgrenar för andra operativsystem.

      En demon utan omstartsförmåga

      Låt oss först skriva en liten server som kan acceptera förfrågningar i JSON-format och ge något slags svar. Till exempel kommer det att returnera antalet element i arrayen som kom i begäran.

      Demonen lyssnar på port 31337. Utdata bör vara ungefär så här:

      $ telnet localhost 31337 Försöker 127.0.0.1 ... Ansluten till localhost. Escape-tecken är "^]. ("hash": 1) # användarinmatning "Begäran hade 1 nycklar" ("hash": 1, "cnt": 2) # användarinmatning "Begäran hade 2 nycklar"

      Vi kommer att använda stream_socket_server () för att börja lyssna på porten och stream_select () för att avgöra vilka deskriptorer som är redo att läsa/skriva.

      Enklaste implementeringskoden (Simple.php)

      stream) * / privata $-strömmar =; / ** @var sträng (client_id => läsbuffert) * / privat $ read_buf =; / ** @var sträng (client_id => skrivbuffert) * / privat $ write_buf =; / ** @var resurs (client_id => ström från vilken man kan läsa) * / privat $ read =; / ** @var resurs (client_id => ström var att skriva) * / privat $ write =; / ** @var int Totalt antal anslutningar * / privat $ conn_count = 0; public function run () ($ this-> listen (); echo "Entering main loop \ n"; $ this-> mainLoop ();) skyddad funktion lyssna () ($ port = self :: PORT; $ ip_port = " 0.0.0.0:$port "; $ adress =" tcp: // $ ip_port "; $ server = stream_socket_server ($ adress, $ errno, $ errstr, STREAM_SERVER_BIND | STREAM_SERVER_LISTEN); om (! $ Server) (fwrite (STDERR, "stream_socket_server misslyckades: $ errno $ errstr \ n"); avsluta (1);) $ this-> read = $ server; eko "Lyssnar på $ adress \ n";) offentlig funktionssvar ($ stream_id, $ svar) ( $ json_resp = json_encode ($ svar); eko "ström $ stream_id". $ json_resp. "\ n"; $ detta-> skriv ($ 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];)) offentlig funktion acceptera ($ server) (eko "Accepterar ny anslutning \ n"; $ client = stream_socket_accept ($ server, 1, $ peername); $ stream_id = ($ this-> conn_count + +); if (! $ klient) (fwrite (STDERR, "Acceptera misslyckades \ n"); return;) stream_set_read_buffer ($ klient, 0); stream_set_write_buffer ($-klient, 0); stream_set_blocking ($ klient, 0); stream_set_timeout ($ klient, 1); $ this-> read_buf [$ stream_id] = ""; $ this-> write_buf [$ stream_id] = ""; $ this-> read [$ stream_id] = $ this-> streams [$ stream_id] = $ klient; echo "Ansluten ström $ stream_id: $ peername \ n"; ) privat funktion koppla från ($ stream_id) (eko "Koppla bort ström $ stream_id \ n"; avaktiverad ($ this-> read_buf [$ stream_id], $ this-> write_buf [$ stream_id]); avaktiverad ($ this-> streams [ $ stream_id]); avaktiverad ($ this-> skriv [$ stream_id], $ this-> read [$ stream_id]);) privat funktion handleRead ($ stream_id) ($ buf = fread ($ this-> streams [$ stream_id]) ], 8192); if ($ buf === falskt || $ buf === "") (eko "fick EOF från stream $ stream_id \ n"; if (tom ($ this-> write_buf [$ stream_id]) ) ($ detta-> koppla från ($ stream_id);) else (avaktiverat ($ this-> read [$ stream_id]);) return;) $ this-> read_buf [$ stream_id]. = $ buf; $ this-> processJSONRequests ($ stream_id);) privat funktion processJSONRequests ($ stream_id) (om (! strpos ($ this-> read_buf [$ stream_id], "\ n")) returnerar; $ requests = explodera ("\ n", $ this -> read_buf [$ stream_id]); $ this-> read_buf [$ stream_id] = array_pop ($ begäranden); foreach ($ begäranden som $ req) ($ res = json_decode (rtrim ($ req), true); if ( $ res! == false) ($ detta-> svar ($ stream_id, "Request had". count ($ res). "nycklar");) else ($ this-> svar ($ stream_id, "Ogiltig JSON");)) ) privat funktion handleWrite ($ stream_id) (if (! isset ($ this-> write_buf [$ stream_id])) (return;) $ skrev = fwrite ($ this-> streams [$ stream_id], substr ($ this-> write_buf [$ stream_id], 0, 65536)); if ($ skrev === false) (fwrite (STDERR, "skriv misslyckades i ström # $ stream_id \ n"); $ detta-> koppla bort ($ stream_id); returnera ;) if ($ skrev === strlen ($ this-> write_buf [$ stream_id])) ($ this-> write_buf [$ stream_id] = ""; avaktiverad ($ this-> write [$ stream_id]); if (tom ($ detta-> läs [$ stream_id])) ($ detta-> koppla från ($ stream_id);)) else ($ this-> write_buf [$ stream_id] = substr ($ this-> write_buf [$ stream_id] , $ skrev);)) offentlig funktion mainLoop () (medan (true) ($ read = $ this-> read; $ write = $ this-> write; $ except = null; eko "Väljer för". count ($ läs). "läser",". count ($ skriv). "skriver \ n"; $ n = stream_select ($ läs, $ skriv, $ förutom, NULL); if (! $ n) (fwrite (STDERR, "Kunde inte stream_select () \ n");) if (count ($ read)) (eko "Kan läsa från". count ($ read). "streams \ n" ;) if (räkna ($ skriv)) (eko "Kan skriva till". count ($ skriv). "strömmar \ n";) if (isset ($ läs)) ($ detta-> acceptera ($ läs); unset ($ read);) foreach ($ läs som $ stream_id => $ _) ($ this-> handleRead ($ stream_id);) foreach ($ skriv som $ stream_id => $ _) ($ this-> handleWrite ( $ stream_id);)))) $ instans = ny Enkel (); $ instans-> kör ();


      Koden för denna demon är mer än standard, men jag skulle vilja notera en implementeringsdetalj: vi lagrar alla läs- och skrivbuffertar med bindning till specifika anslutningar och utför förfrågningsbearbetning direkt på samma plats där vi läser förfrågan. Detta är viktigt eftersom en av dessa förfrågningar kan startas om, i vilket fall det inte kommer att behandla nästa förfrågningar. Men eftersom vi inte har läst förfrågningarna ännu, nästa gång stream_select () från samma deskriptorer kommer att returnera samma resultat. Således kommer vi inte att förlora en enda begäran om vi startar om direkt från kommandohanteraren (förutom när vi skickas flera kommandon samtidigt till samma anslutning, och ett av dessa kommandon kommer att vara omstart).

      Så hur gör du det möjligt att starta om demonen?

      Daemon med omstart och spara etablerade anslutningar

      Vårt enklaste exempel visste inte hur man gjorde något användbart, så låt oss fortfarande skriva demonen som diskuterades i början. Vi vill ta emot något i stil med följande (kommandon skickas till demonen i formen "kommandonamn [JSON-data]", svaret är i form av JSON):
      $ telnet localhost 31337 Försöker 127.0.0.1 ... Ansluten till localhost. Escape-tecken är "^]. # fråga omedelbart demonen att starta om omstart # svaret skickas av den redan omstartade demonen "Omstartad framgångsrikt" # kör testklassens körning ("hash": 1, "params":, "class": "TestClass1") # startade framgångsrikt ("error_text": "OK") # starta om demonen igen (dess underordnade TestClass1 körs fortfarande) starta om "Starta om framgångsrikt" # kontrollera statusen för jobbet: kör fortfarande check ("hash": 1) ("error_text" : "Kör fortfarande") # vänta 5 sekunder och kontrollera igen: klassen TestClass1 fungerade framgångsrikt check ("hash": 1) ("retcode": 0) # demonen kommer ihåg alla lanseringar, så du måste frigöra check ("hash" ": 1) ("retcode": 0) gratis ("hash": 1) ("error_text": "OK") omstart "Starta om framgångsrikt" # Jag uppdaterade koden, så andra gången ser vi ett annat svar för omstart restart ("error_text": "Starta om framgångsrikt") hejdå Anslutningen stängd av främmande värd.

      Tanken med en omstart är enkel: vi kommer att skapa en fil med all nödvändig information, och vid uppstart kommer vi att försöka läsa den och återställa öppna filbeskrivningar.

      Låt oss först skriva koden för att skriva till omstartsfilen:

      Echo "Skapar omstartsfil ... \ n"; if (! $ res = $ this-> getFdRestartData ()) (fwrite (STDERR, "Kunde inte få omstart av FD-data, avslutar, elegant omstart stöds inte \ n"); exit (0);) / * Stäng alla extra filbeskrivningar som vi inte känner till, inklusive opendir () descriptor :) * / $ dh = opendir ("/ proc / self / fd"); $ fds =; medan (falskt! == ($ fil = readdir ($ dh))) (if ($ file === ".") fortsätt; $ fds = $ fil;) foreach ($ fds som $ fd) (if (! isset ($ this-> known_fds [$ fd])) (fclose (fopen ("php: // fd /". $ fd, "r +"));)) $ contents = serialisera ($ res); if (file_put_contents (self :: RESTART_DIR. self :: RESTART_FILENAME, $ contents)! == strlen ($ contents)) (fwrite (STDERR, "Kunde inte helt skriva omstartsfil \ n"); ta bort länken (self :: RESTART_DIR. själv :: RESTART_FILENAME);)

      Koden för att hämta en array av data (getFdRestartData ()-funktionen) visas nedan:

      $ 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, "Ingen fd i strömmetadata för resurs $ v (nyckel $ k i $ 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 som $ prop) ($ res [$ prop] = $ detta -> $ prop;) returnera $ res;
      Koden tar hänsyn till att vi har 2 typer av egenskaper:

      1. Egenskaper som innehåller resurser med anslutningar: $ restart_fd_resources = ["läs", "skriv", "strömmar"].
      2. Egenskaper som innehåller buffertar och annan anslutningsinformation som kan "serialiseras" rå: $ restart_fd_props = ["read_buf", "write_buf", "conn_count"].
      Vi kommer också ihåg alla fd:er som sparats i omstartsfilen och stänger alla andra (om några), eftersom vi annars kan läcka filbeskrivningar.

      Därefter måste vi ladda den här filen i början och fortsätta att använda öppna deskriptorer, som om ingenting hade hänt :). Koden för två funktioner (laddning av omstartsfilen och laddning av information om filbeskrivningar) visas nedan:

      Om (! File_exists (self :: RESTART_DIR. Self :: RESTART_FILENAME)) (retur;) echo "Starta om filen hittades, försöker använda den \ n"; $ contents = file_get_contents (self :: RESTART_DIR. self :: RESTART_FILENAME); ta bort länken (self :: RESTART_DIR. self :: RESTART_FILENAME); if ($ innehåll === falskt) (fwrite (STDERR, "Kunde inte läsa omstartsfil \ n"); return;) $ res = unserialize ($ innehåll); if (! $ res) (fwrite (STDERR, "Kunde inte avserialisera omstartsfilens innehåll"); return;) foreach (self :: $ restart_props som $ prop) (om (! array_key_exists ($ prop, $ res)) (fwrite (STDERR, "Ingen egenskap $ prop i omstartsfil \ n"); fortsätt;) $ this -> $ prop = $ res [$ prop];) $ this-> loadFdRestartData ($ res);

      Funktionen loadFdRestartData () för att expandera filbeskrivningsmatrisen tillbaka:

      $ fd_resources =; foreach (self :: $ restart_fd_resources som $ prop) (if (! isset ($ res [$ prop])) (fwrite (STDERR, "Property" $ prop "finns inte i omstart fd resurser \ n"); fortsätt; ) $ pp =; foreach ($ res [$ prop] som $ k => $ v) (if (isset ($ fd_resources [$ v])) ($ pp [$ k] = $ fd_resources [$ v];) annat ($ fp = fopen ("php: // fd /". $ v, "r +"); if (! $ fp) (fwrite (STDERR, "Det gick inte att öppna fd = $ v, avslutar \ n") ; avsluta (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;)) $ detta -> $ prop = $ pp;) foreach (self :: $ restart_fd_props som $ prop) (if (! isset ($ res [$ prop])) ( fwrite (STDERR, "Property" $ prop "finns inte i omstart fd egenskaper \ n"); fortsätt;) $ this -> $ prop = $ res [$ prop];)
      Vi återställer värdena för read_buffer och write_buffer för öppna filbeskrivningar och ställer in timeouts. Märkligt nog, efter dessa manipulationer tar PHP ganska lugnt emot () på dessa filbeskrivningar och fortsätter att läsa/skriva till dem normalt, även om det inte vet att dessa är sockets.

      I slutändan måste vi skriva logik för att starta och övervaka arbetarnas exekveringsstatus. Eftersom detta inte är relevant för ämnet för artikeln har den fullständiga implementeringen av demonen lagts ut på github-förvaret, vars länk finns nedan.

      Slutsats

      Så den här artikeln beskrev implementeringen av en demon som kommunicerar med JSON-protokollet och kan köra godtyckliga klasser i separata processer med övervakning av processen för deras exekvering. För att köra individuella klasser används modellen gaffel () per begäran, därför, för att behandla begäran behöver du inte starta om tolken och ladda ramverket, medan det blir möjligt att använda opcode-cachen i CLI. Eftersom demonen måste startas om varje gång koden uppdateras, är det nödvändigt att tillhandahålla en mekanism för smidig omstart av denna demon (i vårt företag uppdateras koden ibland med några minuters mellanrum, i form av "snabbkorrigeringar").

      Omstarten sker genom att execve () systemanropet körs, som ett resultat av vilket alla barn förblir kopplade till föräldern (eftersom processens PID inte ändras under execve ()). Dessutom sparas alla öppna filbeskrivningar, vilket gör att du kan fortsätta att behandla förfrågningar från användare i redan öppna anslutningar. Alla nätverksbuffertar, information om körande barn och om öppna deskriptorer sparas i en separat omstartsfil, som läses av en ny instans av demonen, varefter arbetet fortsätter i standardhändelsslingan.

      Den fullständiga implementeringskoden kan ses på GitHub på följande URL.