MongoDB Einrichtung

Im folgenden möchte ich ein paar Notizen zum Thema MongoDB und Sicherheit machen. Wenn die MongoDB auf einem Server installiert wird, hört diese erst mal nur auf localhost, also auf lokale Verbindungen.

Theoretisch kann nun wenn der Server gehackt wird auch einfach die Datenbank ausgelesen werden. Dies möchten wir verhindern in dem wir nur einen Benutzer hinzufügen. Es ist zwar immer ratsam sehr genügsam mit den Rechten umzugehen. Für diesen ersten Schritt möchten wir jedoch einen Benutzer erstellen der grundsätzlich alles darf. Hierzu müssen wir uns erst einmal zur MongoDB verbinden. Dies tun wir am besten indem wir uns via SSH auf den Server verbinden. Wie schon erwähnt nimmt die frisch installierte MongoDB nur Verbindungen vom lokalen Host an. Dies können wir in diesem Fall über SSH optimal erfüllen. Sind wir auf dem Server angelangt verbinden wir uns via

1
# mongo

mit der MongoDB und landen in der sogenannten MongoShell. Wir sehen auch, dass uns die MongoDB dies vollkommen ohne Benutzer und Passwort erlaubt. Nun fügen wir also einen Benutzer hinzu der grundsätzlich über alle MongoDB Datenbanken Berechtigungen erhält. Wir geben also in die MongoShell folgendes ein:

1
> db.createUser({user: “root”, pwd: “SicheresRootPasswort”, roles: [“root”]})

Nun wird man sich wundern, warum denn immernoch Verbindungen ohne Benutzer und Passwort möglich sind. In einer frischen Installation ist die Rechteverwaltung ausgeschaltet. Dies ändern wir nun, in dem wir in der Datei /etc/mongod.conf folgendes eintragen:

1
auth=true

Nun müssen wir nur noch dafür sorge tragen, dass diese Einstellung auch neu eingelesen wird. Hierzu müssen wir einfach den MongoDB Daemon neu starten. Schnell erledigen wir dies mit

1
# service mongod restart

Nun werden wir feststellen, dass wir auf die MongoDB nicht mehr ohne Benutzer und Passwort zugreifen können. Unser erstes Ziel ist also somit erreicht.

Jetzt haben wir noch ein kleines anderes Anliegen. Wir möchten von unserem Rechner mit einem Management Tool für die MongoDB auf diese zugreifen. Also müssen wir der MongoDB mitteilen, dass diese nicht nur auf lokale Verbindungen hört. Diese Einstellung finden wir ebenfalls wieder unter /etc/mongod.conf. Hier kommentieren wir die komplette Zeile mit bind_ip aus, dies tun wir wie unter Linux Konfigurationsdateien immer mit einem einfachen # vor der entsprechenden Option:

1
#bind_ip = 127.0.0.1

Nun müssen wir auch diese Konfiguration nun laden. Wie oben schon erledigen wir dies mit

1
# service mongod restart

Nun können wir auch von extern auf die MongoDB zugreifen.

Der Wichtigste Punkt dabei ist aber: Immer wenn wir externe Verbindungen auf eine Datenbank zulassen, müssen wir diese mit einem Benutzer und Passwort versehen. Dies haben wir im ersten Schritt schon getan. Wir sind hier also auf der sicheren Seite.

Veröffentlicht unter Allgemein, Server | Verschlagwortet mit , , , | Schreib einen Kommentar

Yii2 Modul override Controller, Model, Views

Yii2 Controllers

In Yii2 gibt es die Möglichkeit Module etc. über composer zu installieren. In der Regel werden sowohl alle Composer Yii2 erweiterungen als auch eigens kopierte Yii2 Module im Verzeichnis „vendor“ abgelegt. Ich gehe hier davon aus dass ein Yii2 Modul „user“ installiert wurde und beispielsweise beim aufrufen der User-Übersicht weitere Daten im Controller geladen werden sollen. Im ersten Schritt erstellen wir also einen Controller der genau dies tut. Wir nennen Ihn hier einfach ExtendedUserController. Nun möchte ich aber nicht das gesamte Yii2 Modul „user“ in meinen frontend Ordner kopieren. Hierzu können wir in unserer Yii2 Konfiguration zusätzlich eine ControllerMap angeben. Dies sieht wie folgt aus:

1
2
3
4
5
6
7
8
  'modules'    => [
    'user' => [
      'class'         => '\vendorname\modules\user\UserModule',
      'controllerMap' => [
        'user' => 'frontend\controllers\ExtendedUserController',
      ],
    ],
  ],

In unserer actionIndex möchten wir nun eine zusätzliche Aktion ausführen bevor wir den View rendern. Hierzu können wir jetzt unsere actionIndex einfach simpel überschreiben.

1
2
3
4
  public function actionIndex() {
    // Aktion die wir ausführen möchten
    return parent::actionIndex();
  }

Über parent::actionIndex() können wir die Originalversion der actionIndex() ansteuern. Möchten wir allerdings andere Daten an den View übergeben oder überhaupt eine vollkommen andere View-Datei rendern, müssen wir uns den Code der Originaldatei kopieren und einfach anpassen. Den aufruf parent::actionIndex() lassen wir dann weg.

 

Yii2 Models

Selbiges wie bei den Controllers geht auch bei den Models. Da dieses Thema in der Regel nicht ganz so Wichtig ist wie die Controller möchte ich nur ganz kurz darauf eingehen. Wir gehen davon aus dass wir ein Model „User“ in unserem user Modul haben. Auch diese Klasse erweitern wir in dem wir eine neue Klasse ExtendedUser erstellen die von der Ursprungsklasse User abstammt. Nun können wir in unserer Konfiguration wie bei den Controller auch die Models angeben:

1
2
3
4
5
6
7
8
9
10
11
12
    'modules' => [
        'user' => [
            'class' => 'vendorname\modules\user\UserModule',
            'components' => [
                'manager' => [
                    // Active record classes
                    'userClass'    => 'frontend\models\ExtendedUser',
                ],
            ],
        ],
        ...
    ],

 

Yii2 Views

Was allerdings für Controller und Models gilt, gilt natürlich auch für Views. Und genau dies ist extrem hilfreich. Gerade wenn man viele und auch gerne fremde Module einsetzt. So hat man die Möglichkeit eigene Ansichten für das fremde Yii2 Modul zu erstellen. Hierzu suchen wir uns den entsprechenden View im Modul raus und geben in der Konfiguration an dass wir hier einen eigenen View haben auf den zurück gegriffen werden soll. Mit folgendem Code sagen wir dass die View Files in unserem themes Ordner zu finden sind:

1
2
3
4
5
6
7
8
9
  'components' => [
    'view' => [
      'theme' => [
        'pathMap' => [
          '@vendor/modules/user/views' => '@app/themes/user/views'
        ],
      ],
    ],
  ],

Nun müssen wir nur noch den entsprechenden View Ordner aus dem Modul kopieren und können nun für das Modul jeweils vollkommen eigene Ansichten machen. In Verbindung zum ersten Abschnitt in dem wir einen Controller (und Model) erweitern, haben wir hier zum umgestalten von fremden Modulen vollkommene Freiheit.

 

Warum?

Warum sollten wir das jedoch so machen? Nun zum einen ist es vollkommen sauber getrennt was unser Code ist und was fremder Code ist. Allerdings haben wir noch einen viel wichtigeren Vorteil dadurch. Alle Yii2 Module und Erweiterungen die wir Beispielsweise über Composer installieren sind weiterhin vollkommen Updatefähig. Wir können uns also jederzeit die neuesten Updates der Erweiterungen über Composer holen und unsere Ansichten werden davon nicht beeinflusst.

Veröffentlicht unter YII2 | Verschlagwortet mit , , , , , , , , , , | Schreib einen Kommentar

YII2 Url Generierung

Seit nun ein paar Wochen ist jetzt Yii2 schon auf dem Markt. So wird es Zeit dass ich euch von Yii2 meine Erfahrungen zeige. Da ich mir erst einmal einige Gedanken machen musste bis ich die erste Url in Yii2 aufgebaut hatte möchte ich euch hier einige Möglichkeiten aufzeigen.

Wenn eine Funktion eine Url erwartet kann man diese einfach in der short Array Syntax angeben. So erstellt man einen Link auf die Action „Login“ des „Site“-Controllers wie folgt:

1
Html::a('Login', ['login'])

Dabei kommt ein Link „index.php?r=site/login“. Möchte man nun auf einen anderen Controller verweisen so gibt man die Url mit einem führenden Slash an. Dies ist gleich geblieben zu Yii 1, jedoch wird in Yii2 dies via short Array Syntax notiert. Wenn wir nun auf den Controller „User“ verweisen möchten, müssen wir dies wie folgt tun:

1
Html::a('Login', ['/user/login'])

Hier erhalten wir einen Link der sich ähnlich wie folgender aufbauen wird „index.php?r=user/login“. Wir möchten jedoch noch einen Schritt weiter gehen und einen Parameter „frontend“ mit dem Wert 1 übergeben. Dies erledigen wir in dem wir ein weiteres Element in das Array einfügen.

1
Html::a('Login', ['/user/login', 'frontend'=>1])

So können wir beliebige Parameter mit der Url weitergeben. Dies war jetzt alles sehr ähnlich wie in Yii1. Wenn wir jedoch nun eine einfache URL generieren möchten ohne weiteres Markup herum so machen wir dies mit der URL-Klasse von Yii. Weitere Informationen zu dieser Klasse können unter folgendem Link aufgerufen werden.

1
2
use yii\helpers\Url;
Url::to(['/user/login']);

So erhalten wir ebenfalls einen verweis zu „index.php?r=user/login“. Jedoch erhalten wir dieses mal nicht ein komplettes Html-Tag mit Label etc. sondern lediglich die reine Url. Diese können wir selbst weiterverwenden. Beispielsweise wenn wir über normales HTML einen Link erstellen. Dabei verhält sich der erste Parameter von Url::to() gleich zu dem zweiten Parameter von HTML::a().

Wenn wir nun noch folgenden Code in unserer Yii2 Konfiguration unter „Components“ mit einbinden:

1
2
3
4
'urlManager' => [
'enablePrettyUrl' => true,
'showScriptName' => false,
],

Dann erhalten wir eine Url die ähnlich folgender aussehen wird „http://domain.tld/user/login“

Veröffentlicht unter YII2 | Verschlagwortet mit , , | Schreib einen Kommentar

Joomla 3 Form Field aus Datenbank

Öfters hat man bei der Entwicklung einer Joomla Komponente das Problem dass man eine Benutzerdefinierte Auswalliste (Select-Box) machen möchte. Das folgende Vorgehen was ich beschreiben werde geht sowohl im Backend als auch im Frontend. Als Basis nehme ich an dass eine Komponente schon besteht und diese nun um ein Auswahlfeld erweitert werden soll. Dabei werden wir einen Index haben also einen Value der dann den Wert den wir auswählen darstellt, sowie eine Darstellbare Option für jeden Punkt der Auswahlliste.

Um ein neues Form field unserer Komponente hinzufügen zu können müssen wir im „model“ Verzeichnis unserer Joomla Komponente ein neues Verzeichnis „fields“ erstellen. In dieses Verzeichnis packen wir eine PHP-Datei mit dem namen unseres form Field typs. Für unser Beispiel Feld benutzen wir hier eine Benutzerdefinierte Länderliste. Da Umlaute hier natürlich nicht so Ideal sind nehmen wir als Feld-Typ „laender“. Im ersten Schritt erstellen wir erst ein mal einen Manuellen Listen-Typ.
Also erstellen wir /models/fields/laender.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<?php
// No direct access to this file
defined('_JEXEC') or die;

// import the list field type
jimport('joomla.form.helper');
JFormHelper::loadFieldClass('list');

/**
 * Klasse für das Form Field Länder
 */

class JFormFieldLaender extends JFormFieldList
{

  /**
   * @var string - Feld Typ
   */

  protected $type = 'Laender';

  /**
   * @return array Bezirke
   */

  protected function getOptions() {
    $options[] = JHTML::_('select.option', 1, 'Deutschland');
    $options[] = JHTML::_('select.option', 2, 'Österreich');
    $options[] = JHTML::_('select.option', 3, 'Schweiz');
    # Setze Array zusammen
    $options = array_merge(parent::getOptions(), $options);

    # Gib die fertigen Select optionen zurück
    return $options;
  }
}

In der ersten Zeile finden wir wie gewohnt die Abfrage ob die Datei innerhalb von Joomla aufgerufen wurde. So dass diese Datei Standalone nicht lauffähig ist. Im Anschluss importieren wir die notwendigen Libraries bzw. Klassen.

Um unseren eigenen Feldtyp zu erstellen benötigen wir eine Klasse die sich JFormFieldType (Type durch den eigenen Namen ersetzen) nennt und von JFormFieldList erbt. Dies ist wichtig damit wir das gesamte notwendige Gerüst drum herum automatisch haben. Anschließend legen wir noch die Eigenschaft $type fest. Dabei müssen wir den Namen unseres Feldes nochmals angeben. Hinweis: Der Name den wir hier immer als Type verwenden ist hinterher auch der Feld-Typ im XML-Formular.
In der Funktion getOptions findet nun unsere gesamte Listenzusammensetzung statt. Hier erstellen wir das Array $options noch manuell. Mir geht es nur darum ein Lauffähiges Beispiel zu haben, wir werden dies nachher noch mit der Datenbank koppeln.

Damit unser Feld-Typ auch im Formular eingelesen wird müssen wir in unserer Formular-Beschreibung einen Hinweis auf die Felder einbauen. Das Formular befindet sich für gewöhnlich unter component/models/forms/ und beginnt mit Folgendem code

1
2
3
<?xml version="1.0" encoding="utf-8"?>
<form>
        <fieldset addfieldpath="/components/com_example/models/fields"                >

Hier ersetzen wir addfieldpath durch unseren Pfad, in diesem Fall müssen wir nur den Component-Name auswechseln. Haben wir das getan, können wir dem Formular ganz einfach unser eigenes Feld hinzufügen.

1
2
3
4
5
6
7
8
9
10
<field
  name="datenbankfeld"
  type="laender"
  label="Label"
  description="Form Field Beschreibung"
  message="Form Field, Beschreibung bei Fehlerfall z.B. bei Required"
  class="inputbox"
  required="false"
  default=""
  />

Nun haben wir unser erstes Formularfeld in unsere Komponente integriert. Wenn wir die Komponente jetzt installieren sollte das natürlich jetzt schon funktionieren. Um die Daten von einer Datenbanktabelle auszulesen, gehe ich von einer Tabelle mit dem namen #__example_laender aus in der zwei Spalten definiert sind, einmal die ID und einmal Title für den Ländernamen. Im folgenden müssen wir unsere Klasse die wir als erstes eingefügt haben wie folgt überarbeiten:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
<?php
// No direct access to this file
defined('_JEXEC') or die;

// import the list field type
jimport('joomla.form.helper');
JFormHelper::loadFieldClass('list');

/**
 * Klasse für das Form Field Länder
 */

class JFormFieldLaender extends JFormFieldList
{
  /**
   * @var string - Feld Typ
   */

  protected $type = 'Laender';

  /**
   * Methode um die Bezirke aus der Datenbank auszulesen
   *
   * @return array Bezirke
   */

  protected function getOptions()
  {
    # Hole Datenbankdaten
    $db = JFactory::getDBO();
    # Erstelle einen neuen Query
    $query = $db->getQuery(true);
    # Von welcher Datenbank soll ausgelesen werden
    $query->from('#__example_laender');
    # Welche Spalten sollen ausgelesen werden.
    $query->select('id,title');
    # Den Query als nächstes Abfrageobjekt setzen
    $db->setQuery((string)$query);
    # Objektliste laden
    $messages = $db->loadObjectList();

    # Erstelle ein Array mit Optionen fürs
    # Selectfeld aus der Datenbankabfrage
    $options = array();
    if ($messages)
    {
      foreach($messages as $message)
      {
        # Erstelle die Optionen fürs Selectfeld
        $options[] = JHtml::_('select.option', $message->id, $message->title);
      }
    }
    # Setze Array zusammen
    $options = array_merge(parent::getOptions(), $options);
    # Gib die fertigen Select optionen zurück
    return $options;
  }
}

Ich gehe davon aus dass wir uns schon mit Datenbankabfragen auskennen und ich diese hier nicht erläutern muss. Mit $db->loadObjectList() hole ich eine Objektliste verpackt in einem Array, über dieses ich mi einer foreach iteriere. Als Letzten Punkt fügen wir noch ein entsprechendes Element wie „Bitte wählen“ mit parent::getOptions in das Array ein und verwendenn dieses nun als eigenen Feld-Typ.

Veröffentlicht unter Joomla! 3 | Verschlagwortet mit , , , , , | Ein Kommentar

Datei Upload mit einem Yii Active Record

Datei Upload mit einem Yii Active Record

 

Ein Datei Upload über ein Active Form in Yii zu realisieren, ist gar nicht so schwer, wie man zunächst annimmt. In diesem Artikel möchte ich eine kleine Anleitung bieten, wie man so etwas realisieren könnte. Dabei greife ich zunächst nicht auf weitere Bibliotheken etc zurück, sondern realisiere so etwas mit den Bordmittel von Yii.

Grundsätzlich muss ein Formular für einen Datei Upload ein “enctype=’multipart/form-data’” enthalten, da sonst Dateien vom Browser erst gar nicht übermittelt werden. Dies können wir bei einem CActiveForm wie folgt realisieren:

1
2
3
4
5
<?php $form=$this->beginWidget('CActiveForm',array(
    'id'=>'app-gutschein-form',
    'enableAjaxValidation'=>false,
    'htmlOptions' => array('enctype' => 'multipart/form-data'),
));

Desweiteren müssen wir dann noch das entsprechende Feld zu einem Datei-Feld ändern.

1
2
3
4
5
6
<div class="row">
  <?php echo $form->labelEx($model,'banner'); ?>
  <?php echo $form->fileField($model,'banner'); ?>
  <?php echo $form->error($model,'banner'); ?>
  <?php echo CHtml::image(Yii::app()->request->baseUrl.'/images/uploads/'.$model->banner,"Bild",array("width"=>200)); ?>
</div>

Da in jedem ActiveRecord in Yii entsprechende Regeln für die Datenübermittlung notwendig sind, müssen wir auch für unsere Datei-Felder hier noch entsprechende regeln definieren. Im Rules Part fügen wir also noch folgende Array’s hinzu:

1
2
array('banner', 'file','types'=>'jpg, gif, png','allowEmpty'=>false,'on'=>'update'),
array('banner', 'length', 'max'=>255, 'on'=>'insert,update'),

Nun müssen wir uns um den Datei-Upload im Yii Controller kümmern. Wir gehen beispielsweise in die actionUpdate(), falls der Dateiupload an dieser Stelle eingebaut werden soll. Hier fragen wir erst den alten Namen des Banners ab und reichen anschließend per Massenzuweisung alle Daten des Formulars an das ActiveRecord weiter. Nun holen wir uns die Instanz des hochgeladenen Bildes über CUploadedFile. Wenn kein Bild hochgeladen wurde, gibt es auch keinen Dateinamen hierzu, also weisen wir hier an, dass das ActiveRecord den bisherigen Banner-Namen beibehalten sol,l anderenfalls möchten wir den Namen aus der ActiveRecord_id, dem String “_banner” und dem bisherigen Dateinamen abspeichern. Nach dem Speichern des ActiveRecord Objektes fragen wir zunächst noch einmal ab, ob eine Datei hochgeladen wurde und Speichern die Datei anschließend in Images/Uploads des Arbeitsverzeichnisses.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
if(isset($_POST['ArObject']))
{
  $filename_banner_old = $model->banner;
  $model->attributes=$_POST['ArObject'];
  $uploaded_banner = CUploadedFile::getInstance($model, 'banner');
  if(empty($uploaded_banner)){
    $model->banner = $filename_banner_old;
  }else{
    $filename_banner = $model->id.'_banner'.$uploaded_banner;
    $model->banner = $filename_banner;
  }
  if($model->save()){
    if(!empty($uploaded_banner)){
      $uploaded_banner->saveAs(Yii::app()->basePath.'/../images/uploads/'.$filename_banner);
    }
    $this->redirect("index.php");
  }
}

Hier wurde noch nicht berücksichtigt, wann eine Datei wieder gelöscht wird. Dies muss unter Umständen natürlich auch noch geschehen.

Wenn es noch einen einfacheren Weg gibt, eine Datei hochzuladen, so lasst es mich wissen.

Veröffentlicht unter YII | Verschlagwortet mit , , , , , , , , , | Schreib einen Kommentar

Yii Bootstrap

Das Yii Bootstrap von Christoffer Niska macht es auf einfache Weise möglich, das Twitter Bootstrap in Yii Projekten zu verwenden. Das Twitter Bootstrap ist eine Sammlung von CSS Befehlen, die schon ein recht gutes Layout vorgeben. Es gab eine Zeit lang, da hat sich das Twitter Bootstrap ohne Ende verbreitet und jeder wollte es verwenden. Auch heute gibt es immer mehr Anhänger des Twitter Bootstrap. Was im Twitter Bootstrap unabhängig von dem Yii Bootstrap enthalten ist, kann man auf der Twitter Bootstrap Webseite sehen.

Das Yii Bootstrap kann von der Webseite heruntergeladen werden. Anschließend wird das Zip-Archiv entpackt und in das Verzeichnis /protected/extensions/bootstrap verschoben. Wenn man die Standard Themes des Yii Bootstrap verwenden möchte, so kann man das Theme Verzeichnis in das /themes Verzeichnis von Yii kopiert werden.

Da das Yii Bootstrap auch schon viele vorgefertigte Yii-Widgets mitliefert, muss in der Konfiguration natürlich noch etwas hinzugefügt werden:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Yii::setPathOfAlias('bootstrap', dirname(__FILE__).'/../extensions/bootstrap');
 
return array(
    'theme'=>'bootstrap', // requires you to copy the theme under your themes directory
    'modules'=>array(
        'gii'=>array(
            'generatorPaths'=>array(
                'bootstrap.gii',
            ),
        ),
    ),
    'components'=>array(
        'bootstrap'=>array(
            'class'=>'bootstrap.components.Bootstrap',
        ),
    ),
);

 

Wichtig ist hier die erste Zeile mit der der Pfad für die Bootstrap Widgets gesetzt werden.

 

Darüber hinaus bietet Yii Bootstrap auch noch einen Gii-Crud-Generator an,der ebenfalls mit obenstehender Konfiguration eingebunden wird. Wenn wir uns jetzt in unser Gii einloggen, finden wir als untersten Menüpunkt den Yii Bootstrap Gii Generator. Wir können also, wie wir es von Yii schon gewohnt sind, auch mit Gii uns Code generieren lassen, der anschließend mit Yii Bootstrap Widgets ausgeliefert wird.

Im Layout muss das Yii Bootstrap mit folgendem Befehl eingebunden werden:

 

1
Yii::app()->bootstrap->register();

 

Wenn wir jetzt unsere Stylesheet Dateien ganz normal einbinden, wie wir es gewohnt sind, werden wir feststellen, dass das Yii Bootstrap nach unseren fest eingebundenen Stylesheet Dateien eingebunden wird. Dies ist allerdings manchmal nicht ganz sinnvoll, da man ja nicht immer genau den Style des Twitter Bootstrap haben möchte, sondern auf die Formatierung in der Webseite selbst Hand anlegen möchte. Hier habe ich folgenden Weg gefunden, um das Yii Bootstrap einzubinden und doch anschließend noch meine eigene CSS-Datei:

 

1
2
3
4
Yii::app()->bootstrap->register();
$baseUrl = Yii::app()->baseUrl;
$cs = Yii::app()->getClientScript();
$cs->registerCssFile($baseUrl.'/css/style.css');

 

Wenn ich mein Stylesheet nach diesem Schema einbinde, habe ich keine Probleme mehr und kann in meinem Stylesheet nun die Styles des Yii Bootstrap überschreiben.

 

Wer hat das Yii Bootstrap schon einmal eingesetzt und kennt es schon bzw. hat damit schon Erfahrungen gemacht?

 

Veröffentlicht unter YII | Verschlagwortet mit , , , , | Schreib einen Kommentar

E-Mails via SMTP mit Yii versenden

Wenn ich Mails mit einem System wie Yii versenden möchte, mache ich das nicht mit der PHP-Mail Funktion. Der Aufwand, der betrieben werden muss, um eine Mail mit der PHP Funktion zu versenden, ohne dass diese ein hohes Spam-Rating bekommt, ist mir zu hoch.

Nun habe ich mich auf die Suche gemacht nach einer Lösung, mit der der Aufwand nicht so hoch ist, eine E-Mail via SMTP zu versenden. Da ich jedoch auf allen Servern eine Authentifizierung vor den SMTP-Dienst geschaltet habe, ist es notwendig sich bei diesem erst zu Authentifizieren. Ich habe im Erweiterungsverzeichnis von Yii die Extension EMailer gefunden. Mit dieser Erweiterung ist ganz einfach E-Mails via SMTP zu versenden. Die Klasse bzw. Erweiterung stellt nichts weiter nach, als einen Yii-Wrapper für PhpMailer. Wer mit PHP schon mal versucht hat, sich mit dem Thema E-Mail versenden auseinanderzusetzen, ist zwangsläufig schon auf den PhpMailer gestossen.

Um die Erweiterung zu installieren, wird einfach die Zip-Datei heruntergeladen und im Verzeichnis /protected/extensions/mailer kopiert. Anschließend müssen noch folgende Einträge in die Konfigurationsdatei geschrieben werden:

1
2
3
4
5
6
7
8
9
10
11
12
13
$mailer = Yii::app()->mailer;
$mailer->CharSet = 'utf-8';
$mailer->IsSMTP();
$mailer->SMTPAuth = true;
$mailer->Host = 'smtp.domain.tld';
$mailer->Username = 'user@domain.tld';
$mailer->Password = 'secure';
$mailer->From = 'info@domain.tld;
$mailer->FromName = '
Absendername';
$mailer->AddAddress('
E-Mail Adresse');
$mailer->Subject = '
Betreff';
$mailer->Body = '
E-Mail Text';
$mailer->Send();

So wird mit einem relativ kleinen Code in Yii vernünftig eine E-Mail versendet. Für mich ist der Aufwand, eine Mail via Yii zu versenden, so erheblich geringer, zudem die Spam-Gefahr durch ein Postfach wesentlich geringer ist, wie wenn diese mit der PHP mail() Funktion versendet wird.

Was meint Ihr dazu?

Veröffentlicht unter Allgemein | Verschlagwortet mit , , , | Schreib einen Kommentar

Yii CGridView Spalte mit CLinkColumn verlinken

CLinkColumn erleichtert die Arbeit eine Zelle zu verlinken

Im Yii CGridView ist es relativ einfach eine Spalte zu verlinken. Nehmen wir mal als Beispiel an, es gibt eine Spalte in der Lieferanten aufgelistet werden sollen. Viele der Lieferanten besitzen eine Webseite und diese soll im CGridView so angezeigt werden, dass die Webseite direkt verlinkt ist. Yii bringt hierfür die Klasse CLinkColumn mit. Mit der Klasse CLinkColumn können wir eine Spalte direkt verlinken. Eingesetzt wird CLinkColumn wie in dem folgenden Beispiel.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
$this->widget('bootstrap.widgets.CGridView', array(
  'id'=>'kunden-grid',
  'dataProvider'=>$model->search(),
  'filter'=>$model,
  'summaryText'=>'',
  'columns'=>array(
    'id',
    array(
      'class'=>'LinkColumn',
      'header'=>'$data->firma',
      'labelExpression'=>'$data->firma',
      'urlExpression'=>'$data->website',
      'linkHtmlOptions'=>array('target'=>'_blank'),
    ),
    'strasse',
    'plz',
    'ort',
  ),
));

Wir sehen, dass wir also als Spalte ein Array angeben und diesem die Klasse CLinkColumnübergeben. Das ganze hat jedoch einen gravierenden Nachteil, der mir gar nicht gefällt. Ich kann hier keinen Namen einer Eigenschaft eines ActiveRecord übergeben. Dies stört mich aus dem einfachen Grund, dass es mit dem CLinkColumn nicht mehr so einfach wird, Filter-Optionen mitzugeben. Ich bekomme also nicht einfach ohne weiteres eine Filterzelle angezeigt. Außerdem möchte ich, dass die Spaltenbeschriftung genau mit dem ActiveRecord übereinstimmt. Ich habe hierzu eine eigene Klasse abgeleitet, die ich einfach unter “components” abgelegt habe. Die Klasse habe ich LinkColumn genannt und baut sich wie folgt auf:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
class LinkColumn extends CLinkColumn{
  public $filter;

  public $name = null;
  public $sortable=true;

  public function renderFilterCellContent(){
    if(is_string($this->filter))
      echo '<div class="filter-container">'.$this->filter.'</div>';
    else if($this->filter!==false && $this->grid->filter!==null && $this->name!==null && strpos($this->name,'.')===false)
    {
      if(is_array($this->filter))
        echo '<div class="filter-container">'.CHtml::activeDropDownList($this->grid->filter, $this->name, $this->filter, array('id'=>false,'prompt'=>'')).'</div>';
      else if($this->filter===null)
        echo '<div class="filter-container">'.CHtml::activeTextField($this->grid->filter, $this->name, array('id'=>false)).'</div>';
    }
    else
      parent::renderFilterCellContent();
  }

  public function renderHeaderCellContent(){
    if($this->grid->enableSorting && $this->sortable && $this->name!==null)
      echo $this->grid->dataProvider->getSort()->link($this->name,$this->header,array('class'=>'sort-link'));
    else if($this->name!==null && $this->header===null)
    {
      if($this->grid->dataProvider instanceof CActiveDataProvider)
        echo CHtml::encode($this->grid->dataProvider->model->getAttributeLabel($this->name));
      else
        echo CHtml::encode($this->name);
    }
    else
      parent::renderHeaderCellContent();
  }
}

Dies mag im ersten Moment sehr verwirrend aussehen. Doch was habe ich genau getan? Ich habe eigentlich hier nichts weiter gemacht, als eine neue Klasse mit dem Namen LinkColumn von der Klasse CLinkColumn abgeleitet und habe drei Eigenschaften (filter, name, sortable) definiert. Hinzu habe ich noch zwei Methoden (renderFilterCellContent und renderHeaderCellContent) aus der Klasse CDataColumn kopiert. Das Ergebnis was daraus resultiert, ist eine Möglichkeit mit der es mir möglich wird, einen Zelleninhalt zu verlinken unter Angabe eines eigenen Ziels und der Verwendung einer Eigenschaft aus dem CActiveRecord. Dies sieht dann folgendermaßen aus:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
$this->widget('bootstrap.widgets.CGridView', array(
  'id'=>'kunden-grid',
  'type'=>'striped bordered condensed',
  'dataProvider'=>$model->search(),
  'filter'=>$model,
  'summaryText'=>'',
  'columns'=>array(
    'id',
    array(
      'class'=>'LinkColumn',
      'name'=>'firma',
      'labelExpression'=>'$data->firma',
      'urlExpression'=>'array("view", "id"=>$data->id)',
    ),
    'strasse',
    'plz',
    'ort',
  ),
));

Ich habe diesen ganzen Aufwand eigentlich nur betrieben, um hier noch weiter arbeiten zu können. Hier ging es mir nicht mehr um die Verlinkung einer Externen Seite, sondern um Asyncron daten vom Server holen zu können. Ich suchte eine Möglichkeit, Ajax Links zu generieren, die auch nach dem Pager noch funktionieren. Das Problem mit dem standard Yii Gridview ist, dass ich zwar Ajax Links via CHTML::ajaxLink() auch in eine Zelle generieren kann. Da jedoch das Gridview je Filterauswahl oder Pager Seitenauswahl via Ajax geupdated wird, funktionieren die Ajax Links nicht mehr. Hier musste eine andere Lösung her. Mit meiner neuen LinkColumn Klasse, ist es ganz einfach möglich, eigene Ajax Links zu generieren, die vollkommen unabhängig von Yii sind. Mit folgendem Code generiere ich meine Ajax Links:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
$this->widget('bootstrap.widgets.CGridView', array(
  'id'=>'kunden-grid',
  'type'=>'striped bordered condensed',
  'dataProvider'=>$model->search(),
  'filter'=>$model,
  'summaryText'=>'',
  'columns'=>array(
    'id',
    array(
      'class'=>'LinkColumn',
      'name'=>'notice',
      'labelExpression'=>'Notiz',
      'urlExpression'=>'array("view", "id"=>$data->id)',
      'linkHtmlOptions'=>array('onclick'=>'js:$.ajax({url: $(this).attr("href"),success: function(data){$("#target_id").html(data);}}); return false;'),
    ),
    'strasse',
    'plz',
    'ort',
  ),
));

Was passiert hier genau? Nun ich füge eigentlich nur noch dem verlinkenden A-Tag ein weiteres Attribut “onclick” hinzu und fülle dieses mit einem jQuery Kommando. Vorraussetzung hierfür ist natürlich, dass jQuery standardmäßig auf dieser Seite eingebunden ist. Mit dem jQuery Befehl, führe ich eine Asyncrone Abfrage an den Server durch und kann mir die zurückgelieferten Inhalte hier in einem HTML-Element ausgeben lassen.

Veröffentlicht unter YII | Verschlagwortet mit , , , , | Schreib einen Kommentar

Yii Url beeinflussen

Eine Yii Url bearbeiten

Ich habe mir heute Gedanken gemacht, wie man bei einem Yii Projekt die URL’s SEO gerecht machen kann. Also quasi Yii Speaking Urls. Jedes Projekt, was einen Vermarktungsweg über Google oder Suchmaschinen im allgemeinen findet, benötigt früher oder später noch eine Onpage SEO Optimierung. In Yii haben wir die Möglichkeit, die Yii URL ’s ganz einfach anzupassen. Hier möchte ich einige Beispiele zeigen, wie man diese Aufgabe bewältigen kann.

Konfiguration

In der Basis-Konfiguration können wir einige Parameter einfach anpassen, ohne die Funktionalität zu stören. Wenn wir eine Yii Applikation erstellen, finden wir folgende Konfiguration auskommentiert vor:

1
2
3
4
5
6
7
8
'urlManager'=>array(
  'urlFormat'=>'path',
  'rules'=>array(
    '<controller:\w+>/<id:\d+>'=>'<controller>/view',
    '<controller:\w+>/<action:\w+>/<id:\d+>'=>'<controller>/<action>',
    '<controller:\w+>/<action:\w+>'=>'<controller>/<action>',
  ),
),

Wenn wir diese Konfiguration einkommentieren, bekommen wir eine yii url im Format http://www.domain.tld/index.php/controller/action. Mal angenommen, uns sticht das index.php direkt ins Auge. Dieses möchten wir gerne Entfernen. Nun kommen wir schon nicht mehr ohne eine .htaccess aus. Um unser Ziel zu erreichen müssen wir unsere Konfiguration wie folgt ändern:

1
2
3
4
5
6
7
8
9
'urlManager'=>array(
  'showScriptName'=>false,
  'urlFormat'=>'path',
  'rules'=>array(
    '<controller:\w+>/<id:\d+>'=>'<controller>/view',
    '<controller:\w+>/<action:\w+>/<id:\d+>'=>'<controller>/<action>',
    '<controller:\w+>/<action:\w+>'=>'<controller>/<action>',
  ),
),

Wir fügen hier also noch showScriptName ein und geben dem Konfigurationswert false.
Außerdem müssen wir noch eine .htaccess mit folgendem Inhalt im Hauptverzeichnis (wo die index.php liegt) erstellen.

1
2
3
4
5
6
7
8
RewriteEngine on

# Wenn ein Verzeichnis oder eine Datei Existiert, liefere sie aus
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d

# ansonsten leite Sie weiter zur index.php
RewriteRule . index.php

Was macht den nun dieser Schnipsel hier? Nun wir Prüfen mit den zwei angegebenen RewriteCond Conditions, ob die angeforderte URL ein real existentes Verzeichnis oder eine real existente Datei ist. Ist dies der Fall, so rufen wir diese Datei auf. Ist dies nicht der Fall, rufen wir die index.php auf. Und die ist ja genau unser Eintrittspunkt zum Yii Framework

Klassen

Wir können in Yii auch eine komplette eigene Klasse definieren, um unsere Yii Url für unsere Actions nach unseren Vorstellungen auszugeben. So können wir Beispielsweise auch Speaking Url’s auf Controller Actions vergeben. Denkbar wäre, dass diese im Anschluss über ein Backend verwaltet werden und in der Datenbank gespeichert werden. Im Anschluss könnten wir via ActiveRecord dann diese Daten verwenden. Ich möchte jetzt hier allerdings nicht zu sehr auf diese Klasse eingehen, da dies dann doch so individuell wird, dass ich keine allgemeine Version vorhersehen kann. Eine Beispielklasse könnte wie folgt lauten:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class OwnUrlRule extends CBaseUrlRule
{
    public function createUrl($manager,$route,$params,$ampersand)
    {
        if ($route==='example/index')
        {
            return 'völlig_andere/url';
        }
        return false;
    }
 
    public function parseUrl($manager,$request,$pathInfo,$rawPathInfo)
    {
        if (preg_match('%^(\w+)(/(\w+))?$%', $pathInfo, $matches))
        {
            // hier können wir jetzt prüfen was eingeht.
            // Anschließend sollten wir unsere Url dann wieder in
            // einen Zustand bringen damit Yii etwas damit anfangen
            // kann. Also in ein Format wie controller/action.
        }
        return false;  // this rule does not apply
    }
}

Natürlich müssen wir darauf achten, dass unsere .htaccess Datei auch mit den URL’s die wir erstellen mitspielt. Sonst ist die Seite nicht mehr aufrufbar.

Funktionen

In der Regel verwenden wir zum Beispiel

1
Yii::app()->createUrl('controller/action', array('id' => $this->id))

um eine Yii Url zu erstellen.  Im Prinzip können wir es so sehen dass die Funktion createUrl() aus der oben genannten Klasse verwendet wird.

Veröffentlicht unter YII | Verschlagwortet mit , , , , , , | Schreib einen Kommentar

Das Yii CGridView, wie ich es verwende

In diesem Beitrag möchte ich einige Dinge zum Yii CGridView erläutern und meine Erfahrungen mit dem Yii CGridview darstellen.

In einigen Fällen gibt es Sonderfälle, wo man kein standardisiertes CGridView möchte. Beispielsweise bei der Auflistung einer URL oder eines E-Mail Links.

Standardfall

Wie es von Gii standardmäßig gemacht wird, wird ein Yii CGridView wie folgt erstellt:

1
2
3
4
5
6
7
8
9
10
11
<br />
$this->widget('zii.widgets.grid.CGridView', array(<br />
  'id'=>'beispiel-grid',<br />
  'dataProvider'=>$model->search(),<br />
  'filter'=>$model,<br />
  'columns'=>array(<br />
        'spalte1',<br />
        'spalte2',<br />
        'spalte3',<br />
  ),<br />
));<br />

CGridView weitere Berechnungen oder ein CGridView Link

Doch das Yii CGridView kann noch weitaus mehr. Zum Beispiel möchte ich vor der Ausgabe noch Berechnungen durchführen oder wie oben schon beschrieben einen Link generieren, so kann ich hier leider nicht einfach einen PHP-Code Schnipsel angeben. Allerdings wird durchaus PHP verarbeitet, wenn wir es in Anführungszeichen angeben. Eine Url oder eine Berechnung erstellen wir dann wie folgt:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<br />
$this->widget('zii.widgets.grid.CGridView', array(<br />
  'id'=>'beispiel-grid',<br />
  'dataProvider'=>$model->search(),<br />
  'filter'=>$model,<br />
  'columns'=>array(<br />
        array(<br />
            'name'=>'link',<br />
            'type'=>'raw',<br />
            'value'=>'Chtml::link("Zur Webseite", array("$data->link"))',<br />
        ),<br />
        array(<br />
            'name'=>'betrag',<br />
            'type'=>'raw',<br />
            'value'=>'($data->betrag*1.19)',<br />
        ),<br />
        array(<br />
            'name'=>'link',<br />
            'value'=>'Chtml::link("Zur Webseite", array("$data->link"))',<br />
        ),<br />
  ),<br />
));<br />

Yii CGridView Filter – selbst erstellen

Das Yii CGridView erlaubt es uns auch, in der Filter Zeile eigene Filter zu definieren. So können wir, wie in dem folgenden Beispiel, die Filterzelle auch mit einem Dropdown-Feld füllen. Der Befehl CHtml::listData() erlaubt es uns die Daten an die Filterzelle so zu übergeben, dass daraus ein Dropdown-Feld entsteht. So können wir dann die Suche bzw. das Filtern auf die vorgegebenen Werte des Dropdown Menüs einschränken.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<br />
$this->widget('zii.widgets.grid.CGridView', array(<br />
  'id'=>'beispiel-grid',<br />
  'dataProvider'=>$model->search(),<br />
  'filter'=>$model,<br />
  'columns'=>array(<br />
        array(<br />
            'name'=>'link',<br />
            'type'=>'raw',<br />
            'filter'=>CHtml::listData(Benuzter::model()->links()->findAll(), 'url', 'name'),<br />
            'value'=>'Chtml::link("Zur Webseite", array("$data->link"))',<br />
        ),<br />
        array(<br />
            'name'=>'betrag',<br />
            'type'=>'raw',<br />
            'value'=>'($data->betrag*1.19)',<br />
        ),<br />
        array(<br />
            'name'=>'link',<br />
            'value'=>'Chtml::link("Zur Webseite", array("$data->link"))',<br />
        ),<br />
  ),<br />
));<br />

Yii CGridView Pagination

Wie die Pagination verändert und gesteuert werden kann, werde ich bei Gelegenheit in einem weiteren Artikel zeigen.

Sagt mir Eure Themen, die ich für euch in diesem Blog bearbeiten soll?

Veröffentlicht unter YII | Verschlagwortet mit , , , | Schreib einen Kommentar