htaccess nutzt browser-caching für bilder und css
<p>ich versuche, eine htaccess-datei für meine website zu erstellen, und die pagespeed-erkenntnisse haben gezeigt, dass es bilder und eine css-datei ohne ablauf gibt. </p><p>ich bin nicht sicher, wo ich damit anfangen soll oder wie ich es tun soll. ich habe diesen code aus einem online-lernprogramm und habe mich gefragt, ob dies ausreicht, um zu funktionieren. </p><pre><code>&lt;ifmodule mod\_expires.c&gt; expiresactive on  ## add default expires header ## http://developer.yahoo.com/performance/rules.html#expires &lt;filesmatch "\.(ico|pdf|flv|jpg|jpeg|png|gif|js|css|swf)$"&gt; expiresdefault "access plus 1 year" &lt;/filesmatch&gt; &lt;/ifmodule&gt; </code></pre><p>oder macht dieser code das, was ich brauche?</p><p>vielen dank</p>
<p>versuche etwas wie</p><pre><code>&lt;ifmodule mod\_expires.c&gt; expiresactive on expiresdefault "access plus 1 seconds" expiresbytype text/html "access plus 1 seconds" expiresbytype image/x-icon "access plus 2592000 seconds" expiresbytype image/gif "access plus 2592000 seconds" expiresbytype image/jpeg "access plus 2592000 seconds" expiresbytype image/png "access plus 2592000 seconds" expiresbytype text/css "access plus 604800 seconds" expiresbytype text/javascript "access plus 86400 seconds" expiresbytype application/x-javascript "access plus 86400 seconds" &lt;/ifmodule&gt; </code></pre><p>oder </p><pre><code>&lt;filesmatch "\.(?i:gif|jpe?g|png|ico|css|js|swf)$"&gt; &lt;ifmodule mod\_headers.c&gt; header set cache-control "max-age=172800, public, must-revalidate" &lt;/ifmodule&gt; &lt;/filesmatch&gt; </code></pre>
<p>wie aus den aktualisierungen der ursprünglichen frage hervorgeht, konnte ich meinen code zum laufen bringen, obwohl ich com\_ajax nicht verwendet und meine eigene komponente darauf aufgebaut habe. es gab ein paar haken auf dem weg, aber durch das erstellen meiner eigenen kleinen komponente bekam ich den code so, wie ich es brauchte.</p><p>dazu musste ich der .htaccess-datei der joomla-umgebung einen cors-header hinzufügen, der die daten (site j aus meiner ursprünglichen frage) für access control allow origin (in apache: header-set access-control-allow-origin) verarbeitet. <a href="https://your.originating.site">https://your.originating.site</a> '), um zugriff auf die gehostete umgebung zu erhalten. ich bekam immer eine 301 ohne.</p><p>zuletzt möchte php eine html-datei zurückgeben. genau das tut es. der befehl exit () beendet das skript, bevor die homepage der zielwebsite für sie "zurückgegeben" wird. vielleicht ein wenig eine etwas harte herangehensweise, aber es funktioniert und wird meinen bedürfnissen entsprechen.</p><p>nochmals vielen dank an diejenigen, die geantwortet haben. es half mir, in die richtung zu weisen, die ich brauchte.</p><p>um daten an meine kleine komponente (com\_reverse) zu "pushen", habe ich ein jquery.get und ein curl get verwendet.</p><p>jquery (aus javascript, der kürze halber vereinfacht)</p><pre><code>jquery.get("https://my.joomla.site/index.php?option=com\_reverse", {"text\_str": "text string to reverse"}, function(result) { alert(result) }); </code></pre><p>curl (aus php wiederum der kürze halber vereinfacht)</p><pre><code>$ch = curl\_init(); // initialize curl $curl\_url = "https://my.joomls.site/index.php?option=com\_reverse" . "&amp;text\_str=" . urlencode("string to reverse") //curl\_setopt( $ch, curlopt\_get, 1 ); // get is the default curl\_setopt($ch, curlopt\_url, $curl\_url); curl\_setopt($ch, curlopt\_ssl\_verifyhost,0); curl\_setopt($ch, curlopt\_ssl\_verifypeer, 0); curl\_setopt($ch, curlopt\_returntransfer, 1 ); curl\_setopt($ch, curlopt\_followlocation, 1); // required for redirects $curl\_result = curl\_exec($ch); curl\_close($ch); echo "curl result: " . $curl\_result; // echos back to calling script </code></pre><p>hinweis: curl get und umleitung haben probleme. sie verlieren unterwegs die url-codierung von zeichenfolgen und ihre zeichenfolgen enden am ersten leerzeichen. dies ist für mich kein großes problem, da die meisten daten, die ich verwenden werde, numerisch sind. um dies zu überwinden, ändere ich einfach "" in "~" in meinen zeichenketten und kehre das vor dem "echo" um. wenn jemand eine möglichkeit kennt, die url-codierung über 2 oder 3 weiterleitungen aufrechtzuerhalten, würde ich gerne wissen, wie (es gibt viele curl-optionen, die ich noch nicht untersucht habe).</p><p>hinweis 2: sie sollten einige sicherheitsfunktionen integrieren, wenn sie dies tun möchten. ich werde ein paar schecks in meinen endgültigen code einfügen. dies war nur um herauszufinden, was funktionieren würde.</p> <p>sie können alle ihre benutzerdefinierten css-definitionen im ordner <strong> yourjoomla/templates/yourtemplate/css </strong> ablegen, wenn sie in diesem ordner eine datei custom.css oder user.css erstellen. da dies nicht immer mit allen vorlagen funktioniert, können sie ein kostenloses plugin zum laden ihrer benutzerdefinierten css-codes/stile verwenden:</p><p> <a href="https://extensions.joomla.org/extension/add-custom-css/">https://extensions.joomla.org/extension/add-custom-css/</a> </p><p>auf diese weise können sie ihre 'speziellen' div-klassenstile auch in anderen artikeln wiederverwenden und müssen div-stile nicht artikel für artikel definieren ...</p><p>und ich habe wirklich vergessen zu erwähnen, dass sie zum beispiel den codemirror-editor in ihrem joomla verwenden müssen und sie in diesem fall die artikel im vollständigen html-modus bearbeiten können, den sie unter <strong> global configuration-&gt; default editor einstellen können -&gt; editor-codemirro </strong> r. und auf diese weise können sie zusammen mit der obigen styling-lösung oder mit inline-styling jede art von html-seiten/artikeln erstellen. (es tut mir leid, dass ich diesen wichtigen teil meiner antwort weggelassen habe).</p><p><strong> sehr wichtig bei der verwendung dieses css-lade-plugins: </strong> sie müssen dieses plugin am ende der plugin-reihenfolge im plugin-manager einfügen.</p><p><strong> ergebnisse meiner prüfung der oben genannten: </strong></p><p><strong> mein artikel html: </strong></p><pre><code>&lt;div class="col"&gt; &lt;div class="coll\_1"&gt; &lt;p&gt; this is col 1 &lt;/p&gt; &lt;/div&gt; &lt;div class="coll\_2"&gt; &lt;p&gt; this is col 2 &lt;/p&gt; &lt;/div&gt; &lt;/div&gt; </code></pre><p><strong> mein kurzes css in der datei custom.css: </strong></p><pre><code>.coll\_1 { width: 100px; height: 50px; background-color: red; } .coll\_2 { width: 200px; height:50px; background-color: blue; } </code></pre><p>und mein visuelles ergebnis im artikel im joomla-frontend:</p><p> <a href="https://i.stack.imgur.com/j4atv.jpg"><img src="https://i.stack.imgur.com/j4atv.jpg" alt="custom css loading in joomla with add custom css plugin"></a> </p><p>so funktioniert es problemlos.</p><p><strong> aber das ganze thema viel einfacher machen: </strong> wenn sie <strong> codemirror </strong> als ihren <strong> standard-editor in joomla verwenden , </strong> dann brauchen sie das add custom css plugin eigentlich nicht, um ihre artikel zu stylen. mit dem codemirror-editor können sie einfach ihren inline-css-stil innerhalb von <code>&lt;style&gt;</code> - tags im artikel platzieren, den artikel speichern und das gleiche ergebnis erhalten (einen gestalteten artikel). fügen sie also einfach das ganze in einen ein der artikel und sie werden das haben.</p><p><strong> dann sollte ihr artikel so aussehen: </strong></p><pre><code>&lt;div class="col"&gt; &lt;div class="coll\_1"&gt; &lt;p&gt; this is col 1 &lt;/p&gt; &lt;/div&gt; &lt;div class="coll\_2"&gt; &lt;p&gt; this is col 2 &lt;/p&gt; &lt;/div&gt; &lt;/div&gt; &lt;style&gt; .coll\_1 { width: 100px; height: 50px; background-color: red; } .coll\_2 { width: 200px; height:50px; background-color: blue; } &lt;/style&gt; </code></pre><p><strong> und zum schluss: </strong> sie können sogar <strong> bootstrap </strong> mit codemirror editor in joomla inline importieren/laden, wenn es nicht standardmäßig in ihrer seite geladen ist . sie können bootstrap in ein 'leeres' modul laden, wenn es nicht geladen ist, und sie können bootstrap auch das styling verwenden, wie sie möchten. ich verwende meistens <strong> uikit bibliothek </strong> in layouts und stilen.</p><p>wenn sie diesen code einfach kopieren und in ihren artikel einfügen, erhalten sie 3 spaltenunterteile im artikel, wobei bootstrap (dies ist nur ein beispiel und nicht das laden von bootstrap langfristig):</p><pre><code>&lt;div class="col"&gt; &lt;div class="coll\_1"&gt; &lt;p&gt; this is row1 1 &lt;/p&gt; &lt;/div&gt; &lt;div class="coll\_2"&gt; &lt;p&gt; this is row2 2 &lt;/p&gt; &lt;/div&gt; &lt;div class="coll\_3"&gt; &lt;p&gt; this is row 3 &lt;/p&gt; &lt;/div&gt; &lt;/div&gt; &lt;link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-gn5384xqq1aowxa+058rxpxpg6fy4iwvtnh0e263xmfcjlsawiggfaw/dais6jxm" crossorigin="anonymous"&gt; &lt;div class="container-fluid"&gt; &lt;div class="row"&gt; &lt;div class="col-sm"&gt; one of three columns &lt;/div&gt; &lt;div class="col-sm"&gt; second of three columns &lt;/div&gt; &lt;div class="col-sm"&gt; third of three columns &lt;/div&gt; &lt;/div&gt; &lt;/div&gt; &lt;style&gt; .coll\_1 { width: 100px; height: 50px; background-color: red; } .coll\_2 { width: 200px; height:50px; background-color: blue; } .coll\_3 { width: 100px; height: 50px; } &lt;/style&gt; </code></pre><p>und das ergebnis mit bootstrap wo sie die 3 spalten einteilung sehen können:</p><p> <a href="https://i.stack.imgur.com/gfkff.jpg"><img src="https://i.stack.imgur.com/gfkff.jpg" alt="codemirror editor using bootstrap"></a> </p><p>mit dem codemirror-editor in joomla können sie also endlose dinge tun.</p> Ein reg-ex wird viel schneller sein als html agility pack. 

 Aber Sie sollten bedenken, dass HTML nicht immer gut geformt sein muss. Die Suche nach den richtigen Daten, die Sie nur mit reg-ex verwenden möchten, kann fehlschlagen. Browser sind sehr fehlerverzeihend. 

 Agility Pack ist ein großartiges Werkzeug. Es bietet eine Menge Funktionen für den Speicher, den es verbraucht. <p>nein - es ist ein alter und bekannter weg - nur relativ selten benutzt.</p><p> <a href="http://en.wikipedia.org/wiki/data\_uri\_scheme">http://en.wikipedia.org/wiki/data\_uri\_scheme</a> </p><p>das bild ist teil der seite selbst und wird bei jedem seitenaufruf übertragen und kann daher nicht vom browser zwischengespeichert werden, sodass sie mehr verkehr ausgeben. der vorteil gegenüber standalone-images besteht darin, dass weniger anforderungen an einen server gesendet werden.</p><p>suchen sie nach <a href="http://www.google.co.uk/search?q=data+uri+scheme">daten-uri-schema</a> und sie werden viele beispiele sehen, wie man es benutzt, wann man es benutzt und welche vor- und nachteile es hat.</p> <p>der grund, warum sie denselben inhalt erhalten, liegt in der eigenschaft <code>#cache</code> des render-arrays, die sie beim aufrufen der methode <code>render()</code> erhalten.</p><p>insbesondere setzen sie durch aufrufen von <code>setoffset()</code> früher in ihrem code implizit einen cache-schlüssel für das render-array (siehe <a href="https://api.drupal.org/api/drupal/core%21modules%21views%21src%21viewexecutable.php/function/viewexecutable%3a%3asetoffset/8.2.x">hier</a> ):</p><blockquote> <pre><code>$this-&gt;element['#cache']['keys'][] = 'offset:' . $offset; </code></pre></blockquote><p>diese cache-schlüsseleinstellung in kombination mit der eigenschaft <code>#theme</code> des render-arrays (<code>views\_view</code>), die für beide ansichten gleich ist, führt beim einschließen zu einer zwischengespeicherten version der ersten die zweite, da die kombination [<code>#theme</code>] + [<code>#cache</code>] [schlüssel] für beide ansichten identisch ist.</p><p>um das zu umgehen, könnten sie:</p><ol> <li>entfernen sie das caching für diese ansichten vollständig, oder</li> <li>vermeiden sie die verwendung von <code>setoffset()</code> oder</li> <li> <p>fügen sie dem cache spezifischere schlüssel hinzu, sodass sie für jede ansicht einen anderen cache haben. z.b.</p> <pre><code>$variables['viewcalls']['#cache']['keys'] = array\_merge( $variables['viewcalls']['#cache']['keys'], array('viewcalls') ); ... $variables['viewappointments']['#cache']['keys'] = array\_merge( $variables['viewappointments']['#cache']['keys'], array('viewappointments') ); </code></pre></li> </ol><p>ich habe ihren fall mit der option 3. getestet und es hat wie erwartet funktioniert. bevor sie sich für die verwendung eines anderen moduls entschieden haben, können sie versuchen, an ihrem ursprünglichen code festzuhalten und die eigenschaft <code>#cache</code> beide render-arrays entsprechend zu ändern.</p><p>viel glück!</p> hi @gulfo,die verärgerung kann ich verstehe, nur ist die antwort von @kenneth nicht automatisiert.sicher hast du schon davon gehört, dass wir als online mediathek unseren lizenzgebern gegenüber verpflichtet sind, die uns zur verfügung gestellten inhalte mit einem kopierschutz zu versehen. dieser kopierschutz wird stetig erweitert und den aktuellen gegebenheiten angepasst. durch die aktuellen anpassungen am kopierschutz kann es dazu kommen, dass der abruf mit einer älteren version deines browsers nicht mehr möglich ist. um dem vorzubeugen, müssen die von uns unterstützten browser (microsoft edge, google chrome, mozilla firefox und safari)auf der aktuellsten version laufen. darauf wollte kenneth nur hinaus.wenn alle aktualisierungen gemacht sind, fülle uns bitte die im nachfolgenden artikel stehende datenabfrage aus. mithilfe der dann erfolgenden daten können wir weiter nach der die fehlermeldungen auslösenden ursache suchen: <p><code>hook\_init()</code> wird von drupal nur einmal für jede angeforderte seite aufgerufen; dies ist der letzte schritt in <a href="http://api.drupal.org/api/drupal/includes!common.inc/function/\_drupal\_bootstrap\_full/7">\_ drupal\_bootstrap\_full ()</a> .</p><pre><code> // drupal 6 // // let all modules take action before menu system handles the request // we do not want this while running update.php. if (!defined('maintenance\_mode') || maintenance\_mode != 'update') { module\_invoke\_all('init'); } </code></pre><pre><code> // drupal 7 // // let all modules take action before the menu system handles the request. // we do not want this while running update.php. if (!defined('maintenance\_mode') || maintenance\_mode != 'update') { // prior to invoking hook\_init(), initialize the theme (potentially a custom // one for this page), so that: // - modules with hook\_init() implementations that call theme() or // theme\_get\_registry() don't initialize the incorrect theme. // - the theme can have hook\_*\_alter() implementations affect page building // (e.g., hook\_form\_alter(), hook\_node\_view\_alter(), hook\_page\_alter()), // ahead of when rendering starts. menu\_set\_custom\_theme(); drupal\_theme\_initialize(); module\_invoke\_all('init'); } </code></pre><p>wenn <code>hook\_init()</code> mehrmals ausgeführt wird, sollten sie herausfinden, warum dies geschieht. soweit ich sehen kann, überprüft keine der implementierungen von <code>hook\_init()</code> in drupal, dass sie zweimal ausgeführt wird (siehe zum beispiel <a href="http://api.drupal.org/api/drupal/modules!system!system.module/function/system\_init/7">system\_init ()</a> oder - <a href="http://api.drupal.org/api/drupal/modules!update!update.module/function/update\_init/7">pdate\_init ()</a> ). wenn dies normalerweise bei drupal der fall ist, prüft <code>update\_init()</code> zunächst, ob es bereits ausgeführt wurde.</p><p>wenn der zähler die anzahl der aufeinanderfolgenden tage ist, an denen sich ein benutzer angemeldet hat, würde ich lieber <code>hook\_init()</code> mit einem code implementieren, der dem folgenden ähnlich ist.</p><pre><code>// drupal 7 function mymodule\_init() { global $user; $result = mymodule\_increase\_counter($user-&gt;uid); if ($result[0]) { // increase the counter; set the other variables. } elseif ($result[1] &gt; 86400) { // the user didn't log in yesterday. } } function mymodule\_date($timestamp) { $date\_time = date\_create('@' . $timestamp); return date\_format($date\_time, 'ymd'); } function mymodule\_increase\_counter($uid) { $last\_timestamp = variable\_get("mymodule\_last\_timestamp\_$uid", 0); if ($last\_timestamp == request\_time) { return array(false, 0); } $result = array( mymodule\_date($last\_timestamp + 86400) == mymodule\_date(request\_time), request\_time - $last\_timestamp, ); variable\_set("mymodule\_last\_timestamp\_$uid", request\_time); return $result; } </code></pre><pre><code>// drupal 6 function mymodule\_init() { global $user; $result = mymodule\_increase\_counter($user-&gt;uid); if ($result[0]) { // increase the counter; set the other variables. } elseif ($result[1] &gt; 86400) { // the user didn't log in yesterday. } } function mymodule\_increase\_counter($uid) { $last\_timestamp = variable\_get("mymodule\_last\_timestamp\_$uid", 0); $result = array(false, time() - $last\_timestamp); if (time() - $last\_timestamp &lt; 20) { return $result; } $result[0] = (mymodule\_date($last\_timestamp + 86400) == mymodule\_date(request\_time)); variable\_set("mymodule\_last\_timestamp\_$uid", time()); return $result; } </code></pre><p>wenn <code>hook\_init()</code> während derselben seitenanforderung zweimal hintereinander aufgerufen wird, enthält <code>request\_time</code> diesen wert und die funktion würde <code>false</code> zurückgeben.</p><p>der code in <code>mymodule\_increase\_counter()</code> ist nicht optimiert; es soll nur ein beispiel zeigen. in einem realen modul würde ich lieber eine datenbanktabelle verwenden, in der der zähler und die anderen variablen gespeichert sind. der grund ist, dass drupal variablen alle in die globale variable <code>$conf</code> geladen werden, wenn drupal bootstraps (siehe <a href="http://api.drupal.org/api/drupal/includes!bootstrap.inc/function/\_drupal\_bootstrap\_variables/7">\_ drupal\_bootstrap\_variables ()</a> und - <a href="http://api.drupal.org/api/drupal/includes!bootstrap.inc/function/variable\_initialize/7">variable\_initialize ()</a> ); wenn sie dafür drupal -variablen verwenden, lädt drupal informationen über alle benutzer, für die sie informationen gespeichert haben, in den speicher, wenn für jede angeforderte seite nur ein benutzerkonto im gespeichert ist globale variable <code>$user</code>.</p><p>wenn sie die anzahl der von den benutzern an aufeinanderfolgenden tagen besuchten seiten zählen, würde ich den folgenden code implementieren.</p><pre><code>// drupal 7 function mymodule\_init() { global $user; $result = mymodule\_increase\_counter($user-&gt;uid); if ($result[0]) { // increase the counter; set the other variables. } elseif ($result[1] &gt; 86400) { // the user didn't log in yesterday. } } function mymodule\_date($timestamp) { $date\_time = date\_create('@' . $timestamp); return date\_format($date\_time, 'ymd'); } function mymodule\_increase\_counter($uid) { $last\_timestamp = variable\_get("mymodule\_last\_timestamp\_$uid", 0); if ($last\_timestamp == request\_time) { return array(false, 0); } $result = array( mymodule\_date($last\_timestamp + 86400) == mymodule\_date(request\_time), request\_time - $last\_timestamp, ); variable\_set("mymodule\_last\_timestamp\_$uid", request\_time); return $result; } </code></pre><pre><code>// drupal 6 function mymodule\_init() { global $user; $result = mymodule\_increase\_counter($user-&gt;uid); if ($result[0]) { // increase the counter; set the other variables. } elseif ($result[1] &gt; 86400) { // the user didn't log in yesterday. } } function mymodule\_increase\_counter($uid) { $last\_timestamp = variable\_get("mymodule\_last\_timestamp\_$uid", 0); $result = array(false, time() - $last\_timestamp); if (time() - $last\_timestamp &lt; 20) { return $result; } $result[0] = (mymodule\_date($last\_timestamp + 86400) == mymodule\_date(request\_time)); variable\_set("mymodule\_last\_timestamp\_$uid", time()); return $result; } </code></pre><p>sie werden feststellen, dass ich in meinem code nicht <code>$user-&gt;access</code> verwende. der grund ist, dass <code>$user-&gt;access</code> während des bootstraps drupal aktualisiert werden kann, bevor <code>hook\_init()</code> aufgerufen wird. der von drupal verwendete sitzungsschreibhandler enthält den folgenden code. (siehe <a href="http://api.drupal.org/api/drupal/includes!session.inc/function/\_drupal\_session\_write/7">\_ drupal\_session\_write ()</a> .)</p><pre><code>// likewise, do not update access time more than once per 180 seconds. if ($user-&gt;uid &amp;&amp; request\_time - $user-&gt;access &gt; variable\_get('session\_write\_interval', 180)) { db\_update('users') -&gt;fields(array( 'access' =&gt; request\_time, )) -&gt;condition('uid', $user-&gt;uid) -&gt;execute(); } </code></pre><p>für einen anderen hook, den sie verwenden können, können sie mit drupal 7 <a href="http://api.drupal.org/api/drupal/modules!system!system.api.php/function/hook\_page\_alter/7">hook\_page\_alter ()</a> verwenden; sie ändern nur nicht den inhalt von <code>$page</code>, sondern erhöhen ihren zähler und ändern ihre variablen.<br> auf drupal 6 können sie <a href="http://api.drupal.org/api/drupal/developer!hooks!core.php/function/hook\_footer/6">hook\_footer ()</a> verwenden, den hook, der von <a href="http://api.drupal.org/api/drupal/includes!theme.inc/function/template\_preprocess\_page/6">template\_preprocess\_page ()</a> aufgerufen wird. sie geben nichts zurück, sondern erhöhen ihren zähler und ändern ihre variablen.</p><p>auf drupal 6 und drupal 7 können sie <a href="http://api.drupal.org/api/drupal/modules%21system%21system.api.php/function/hook\_exit/7">hook\_exit ()</a> verwenden. beachten sie, dass der hook auch aufgerufen wird, wenn bootstrap nicht vollständig ist. der code konnte keinen zugriff auf funktionen haben, die von modulen oder anderen drupal -funktionen definiert wurden, und sie sollten zuerst überprüfen, ob diese funktionen verfügbar sind. einige funktionen sind immer über <code>hook\_exit()</code> verfügbar, z. b. die in <a href="http://api.drupal.org/api/drupal/includes!bootstrap.inc/7">bootstrap.inc</a> und <a href="http://api.drupal.org/api/drupal/includes!cache.inc/7">cache.inc</a> definierten. der unterschied besteht darin, dass <code>hook\_exit()</code> auch für zwischengespeicherte seiten aufgerufen wird, während <code>hook\_init()</code> für zwischengespeicherte seiten nicht aufgerufen wird.</p><p>als beispiel für code, der von einem drupal -modul verwendet wird, siehe <a href="http://api.drupal.org/api/drupal/modules!statistics!statistics.module/function/statistics\_exit/7">statistics\_exit ()</a> . das statistikmodul protokolliert zugriffsstatistiken für eine site und verwendet, wie sie sehen, <code>hook\_exit()</code> und nicht <code>hook\_init()</code>. um die erforderlichen funktionen aufrufen zu können, wird <a href="http://api.drupal.org/api/drupal/includes!bootstrap.inc/function/drupal\_bootstrap/7">drupal\_bootstrap ()</a> aufgerufen, wobei der richtige parameter übergeben wird, wie im folgenden code.</p><pre><code> // when serving cached pages with the 'page\_cache\_without\_database' // configuration, system variables need to be loaded. this is a major // performance decrease for non-database page caches, but with statistics // module, it is likely to also have 'statistics\_enable\_access\_log' enabled, // in which case we need to bootstrap to the session phase anyway. drupal\_bootstrap(drupal\_bootstrap\_variables); </code></pre><pre><code> if (variable\_get('statistics\_enable\_access\_log', 0)) { drupal\_bootstrap(drupal\_bootstrap\_session); // for anonymous users unicode.inc will not have been loaded. include\_once drupal\_root . '/includes/unicode.inc'; // log this page access. db\_insert('accesslog') -&gt;fields(array( 'title' =&gt; truncate\_utf8(strip\_tags(drupal\_get\_title()), 255), 'path' =&gt; truncate\_utf8($\_get['q'], 255), 'url' =&gt; isset($\_server['http\_referer']) ? $\_server['http\_referer'] : '', 'hostname' =&gt; ip\_address(), 'uid' =&gt; $user-&gt;uid, 'sid' =&gt; session\_id(), 'timer' =&gt; (int) timer\_read('page'), 'timestamp' =&gt; request\_time, )) -&gt;execute(); } </code></pre><h3>aktualisieren</h3><p>möglicherweise gibt es einige verwirrung darüber, wann <code>hook\_init()</code> aufgerufen wird.</p><p><code>hook\_init()</code> wird für jede seitenanforderung aufgerufen, wenn die seite nicht zwischengespeichert ist. es wird nicht einmal für jede seitenanforderung aufgerufen, die vom selben benutzer stammt. wenn sie beispielsweise <a href="http://example.com/admin/appearance/update">http://example.com/admin/appearance/update</a> und dann <a href="http://example.com/admin/reports/status">http://example.com/admin/reports/status</a> besuchen , <code>hook\_init()</code> wird zweimal aufgerufen: eine für jede seite.<br> "der hook wird zweimal aufgerufen" bedeutet, dass es ein modul gibt, das den folgenden code ausführt, sobald drupal seinen bootstrap abgeschlossen hat.</p><pre><code>module\_invoke\_all('init'); </code></pre><p>wenn dies der fall ist, würde die folgende implementierung von <code>hook\_init()</code> zweimal denselben wert anzeigen.</p><pre><code>function mymodule\_init() { watchdog('mymodule', 'request time: !timestamp', array('!timestamp' =&gt; request\_time), watchdog\_debug); } </code></pre><p>wenn ihr code für <code>request\_time</code> zwei werte anzeigt, für die die differenz wie in ihrem fall 2 minuten beträgt, wird der hook nicht zweimal aufgerufen, sondern einmal für jede angeforderte seite, wie es passieren sollte.</p><p><code>request\_time</code> ist in <a href="http://api.drupal.org/api/drupal/includes!bootstrap.inc/7">bootstrap.inc</a> mit der folgenden zeile definiert.</p><pre><code>define('request\_time', (int) $\_server['request\_time']); </code></pre><p>bis die aktuell angeforderte seite nicht an den browser zurückgegeben wird, ändert sich der wert von <code>request\_time</code> nicht. wenn sie einen anderen wert sehen, beobachten sie den auf einer anderen anforderungsseite zugewiesenen wert.</p> <p>geben sie <code>chrome://cache</code> in die adressleiste ein, um eine liste der von chrome zwischengespeicherten ressourcen anzuzeigen.</p><p>wenn sie auf eine ressource klicken, wird leider eine hex + ascii-vorschau des inhalts angezeigt. in fällen, in denen der inhalt gezippt (archiviert) wurde, kann diese vorschau nur gelesen werden, wenn sie mit einem tool verarbeitet wurde, mit dem sie dekomprimiert werden kann.</p> <h2>es kommt darauf an ™</h2><p>die fähigkeit, einen oder mehrere cursor zu umgehen, hängt davon ab, was in diesem cursor ausgeführt wird. ohne zu wissen, was darin vor sich geht, gibt es keine möglichkeit zu sagen. es kann sein, dass es keine problemumgehung gibt und sie eine zeilenweise verarbeitung durchführen müssen.</p><p>nachfolgend einige beispiele.</p><h2>funktioniert nicht in sets</h2><p>dieses beispiel ist das grundlegendste und ist einfach die tatsache, dass sie ihr gesamtes dataset oder teile ihres datasets auf einmal abfragen können, aber der cursor wurde erstellt und fragt die daten zeilenweise ab. übliche, durch die dies ersetzt werden kann, sind <code>join</code>, <code>cross apply</code>/<code>outer apply</code> und andere.</p><p><strong> betrachten sie den folgenden datensatz: </strong></p><pre><code>create table dbo.lotr(lotrid int, charactername varchar(255), val varchar(255)); create table dbo.lotrattributes(lotrattributeid int, lotrid int, attrval varchar(255)); insert into dbo.lotr(lotrid,charactername,val) values(1,'frodo','ring') ,(2,'gandalf','staff'); insert into dbo.lotrattributes(lotrid,lotrattributeid,attrval) values(1,1,'ringattribute1') ,(1,2,'ringattribute2') ,(1,3,'ringattribute3') ,(2,4,'staffattribute1') ,(2,5,'staffattribute2'); </code></pre><p>man könnte versuchen, jeden datensatz zu finden, und er stimmt separat überein, indem man die tabelle <code>lotr</code> durchläuft.</p><p><strong> cursor: </strong></p><pre><code>declare @lotrid int declare c cursor for select lotrid from dbo.lotr; open c fetch next from c into @lotrid; while @@fetch\_status = 0 begin select lotrattributeid from dbo.lotrattributes where lotrid = @lotrid; fetch next from c into @lotrid; end close c deallocate c </code></pre><p><strong> das ergebnis sind zwei ergebnismengen </strong></p><pre><code>lotrattributeid 1 2 3 lotrattributeid 4 5 </code></pre><p><strong> wenn dieses <code>inner join</code> verwendet wird, erhalten wir das gleiche ergebnis wie eine ergebnismenge. </strong></p><pre><code>select lotrattributeid from dbo.lotr l inner join dbo.lotrattributes la on l.lotrid = la.lotrid; lotrattributeid 1 2 3 4 5 </code></pre><hr><h2>string-manipulation</h2><p>häufig wird <code>for xml path('')</code> verwendet, um zeichenfolgenmanipulationen innerhalb von cursorn zu ersetzen.</p><p><strong> datensatz </strong></p><pre><code>create table dbo.lotr(lotrid int, charactername varchar(255), val varchar(255)); create table dbo.lotrattributes(lotrattributeid int, lotrid int, attrval varchar(255)); insert into dbo.lotr(lotrid,charactername,val) values(1,'frodo','ring'); insert into dbo.lotrattributes(lotrid,lotrattributeid,attrval) values(1,1,'ringattribute1') ,(1,2,'ringattribute2') ,(1,3,'ringattribute3'); </code></pre><p><strong> doppelcursor mit string-manipulation </strong></p><pre><code>declare @lotrid int, @charactername varchar(255), @val varchar(255) declare @lotrattributeid int, @attrval varchar(255) declare c cursor for select lotrid,charactername, val from dbo.lotr open c fetch next from c into @lotrid,@charactername,@val while @@fetch\_status = 0 begin set @charactername +='|'+ @val declare d cursor for select lotrattributeid, attrval from dbo.lotrattributes where lotrid = @lotrid open d fetch next from d into @lotrattributeid,@attrval while @@fetch\_status = 0 begin set @charactername +='['+@attrval+ '],' fetch next from d into @lotrattributeid,@attrval end close d deallocate d fetch next from c into @lotrid,@charactername,@val end close c deallocate c select left(@charactername,len(@charactername)-1); </code></pre><p><strong> ergebnis </strong></p><pre><code>(no column name) frodo|ring[ringattribute1],[ringattribute2],[ringattribute3], </code></pre><p><strong> entfernen der cursor mit for xml path ('') </strong></p><pre><code>select l.charactername +'|'+ l.val + (select stuff((select ','+quotename(attrval) from dbo.lotrattributes la where la.lotrid = l.lotrid for xml path('')), 1, 1, '')) from dbo.lotr l; </code></pre><h2>* *</h2><p>die eigentliche problemumgehung besteht darin, herauszufinden, warum die daten auf diese weise dargestellt werden, und die anwendung zu ändern, um sie nicht in diesem format zu benötigen, und sie irgendwo zu speichern.</p><p>wenn ihre hände gebunden sind, wäre dies das nächstbeste.</p><hr><h2>fügen sie die top-10-werte in eine temporäre tabelle ein, basierend auf den ids in einer anderen tabelle</h2><p><strong> daten </strong></p><p>create table dbo.sometable (inserttableid int, val varchar (255)); create table dbo.top10table (top10tableid int, inserttableid int, val varchar (255));</p><pre><code>insert into dbo.sometable(inserttableid,val) values(1,'bla') ,(2,'blabla'); insert into dbo.top10table(top10tableid,inserttableid,val) values(1,1,'wuw') ,(2,1,'wuw') ,(3,1,'wuw'); </code></pre><p><strong> cursor </strong></p><pre><code>create table #top10values(top10tableid int, inserttableid int, val varchar(255)) declare @inserttableid int; declare c cursor for select inserttableid from dbo.sometable; open c fetch next from c into @inserttableid; while @@fetch\_status =0 begin insert into #top10values(top10tableid,inserttableid,val) select top(10) top10tableid,inserttableid,val from dbo.top10table where inserttableid = @inserttableid order by top10tableid fetch next from c into @inserttableid; end close c deallocate c select * from #top10values; drop table #top10values; </code></pre><p><strong> ergebnis </strong></p><pre><code>top10tableid inserttableid val 1 1 wuw 2 1 wuw 3 1 wuw </code></pre><p><strong> ersetzen des cursors durch <code>cross apply</code> und ein <code>cte</code> </strong></p><pre><code>create table #top10values(top10tableid int, inserttableid int, val varchar(255)); ;with cte as ( select inserttableid from dbo.sometable ) insert into #top10values(top10tableid,inserttableid,val) select t1t.top10tableid,t1t.inserttableid,t1t.val from cte cross apply (select top (10) top10tableid,inserttableid,val from dbo.top10table t1t where t1t.inserttableid = cte.inserttableid ) t1t ; select * from #top10values; drop table #top10values; </code></pre><hr><h2>andere beispiele</h2><ul> <li>ein beispiel zum ersetzen eines cursors zur auswahl eines dynamischen satzes von artikeln pro lieferant mithilfe von <code>cross apply</code> <a href="https://dba.stackexchange.com/questions/100761/replacing-a-cursor-with-a-single-query-possible">hier</a> .</li> <li>ein beispiel für die verwendung von fensterfunktionen zum ersetzen eines cursors <a href="https://dba.stackexchange.com/questions/127083/improve-a-query-using-cursor-to-set-based-approach">hier</a> .</li> </ul><hr><p><strong> manchmal gibt es keine andere wahl </strong></p><p>wenn sie nicht in sätzen arbeiten können und zeilenweise arbeiten müssen, können sie den cursor trotzdem optimieren.</p><p>eine der größten änderungen bei der beschleunigung des cursors ist das hinzufügen von <code>local fast\_forward</code>.</p><pre><code>declare c cursor local fast\_forward for select lotrid from dbo.lotr </code></pre><p>schauen sie sich <a href="https://sqlperformance.com/2012/09/t-sql-queries/cursor-options">diesen blogpost</a> von @aaronbertrand an, wo er die möglichen leistungsunterschiede erklärt, wenn cursoreinstellungen wie <code>local</code> &amp; <code>fast\_forward</code> verwenden oder nicht.</p> Ich fand das Buch <http://www.amazon.de/HTML-mit-CSS-XHTML-Kopf/dp/3897214539/> sehr anschaulich und auch unterhaltsam geschrieben. Auf jeden Fall Anfänger geeignet.  

Eine VHS Kurs halte ich dafür nicht für so sinnvoll. Einfach weil es so schwierig nicht ist, dass man da ständig jemanden zum nachfragen bräuchte.