- fchao-Sinus-Wechselrichter AliExpress         
Seite 1 von 4 123 ... LetzteLetzte
Ergebnis 1 bis 10 von 36

Thema: html code für User Login + password (esp8266 + Arduino IDE)

  1. #1
    HaWe
    Gast

    html code für User Login + password (esp8266 + Arduino IDE)

    Anzeige

    LiFePo4 Akku selber bauen - Video
    hi,
    ich komme nicht weiter bei meinem Versuch,eine Funktion mit html code für Login mit username + password zu schreiben (esp8266 + Arduino IDE).
    Sie soll aufgerufen werden, solange eine globale Variable (noch) auf authorized==false steht.
    Dann heißt es in loop:
    if (!authorized) handleLogin(); // Website mit je 1 Feld für username + password
    if (authorized) handleWebsite(); // vollständige Website mit Messwerten

    Kennt jemand einen (möglichst selber schon mal verwendeten) Code, mit dem man einfach nur 2 Felder auf einer html Website hat, um deren Eingabestrings getrennt zu erfassen + 1 Bestätigungs-Button in der Art

    Code:
    Username: [_________]
    
    Password: [_________]
    
           [LOGIN]
    edit - ah, habe das System verstanden, man erhält einen langen String, aus dem man die Einzelstrings der betr. Textfelder herausisolieren muss...
    Geändert von HaWe (09.08.2018 um 11:12 Uhr)

  2. #2
    Erfahrener Benutzer Robotik Einstein
    Registriert seit
    18.03.2018
    Beiträge
    2.650
    Zum Zeitpunkt weiß ich zwar nicht, wie das mit Arduino funktioniert, aber da es ja nur um Webseiten-Verarbeitung geht, muss man sich beim Arduino sicher auch an die Standards halten. Dazu ein kleiner Überblick, wirst Du aber sicher auch schon so oder ähnlich gefunden haben: https://wiki.selfhtml.org/wiki/HTTP/Anfragemethoden

    Die einfachste Methode Formular-Daten zu versenden ist unverschlüsselt. Dazu wird auf dem Webserver eine Seite aufgerufen (z.B. PHP) an die die Werte aus dem Formular geschickt werden. Einfach beispielsweise in etwas so:
    Code:
    http://.../eingabe.xxx?feld1=hallo&feld2=ballo
    Das macht der Client, die Serveranwendung muss die Daten auswerten. Zuerst kommt natürlich der gesamte String so an. Da ist Dir ja auch irgendwo das Licht aufgegangen.

    Bei komplizierteren Strings, die nach dieser Methode geschickt werden sollen, gibt es noch Kodierungsmöglichkeiten, weil man sonst bestimmte Zeichen nicht verschicken kann (wie eben das '=' oder das '&'). Das muss dann Serverseitig decodiert werden, aber eben nur, wenn der Web-Client das auch kodiert verschickt, das liegt dann aber an Dir, ob Du die Login-Seite so programmierst oder nicht.
    Geändert von Moppi (12.08.2018 um 07:38 Uhr)

  3. #3
    HaWe
    Gast
    hallo,
    ja, danke, das mit
    feld1=hallo&feld2=ballo..
    meinte ich oben mit " langen String, aus dem man die Einzelstrings der betr. Textfelder herausisolieren muss".
    Ich verwende kein php, nur html unverschlüsselt, und ich habe auch einen vereinfachten Test-Code fürs Login inzwischen, welcher eine Website aufbaut und dort in 2 Textfeldern nach username und passwort fragt.
    Nur funktioniert es noch nicht mit den neueren esp8266-cores für Arduino, sondern nur mit älteren.
    Wenn es hier html-Fachleute gibt, die versuchen möchten ihn zu debuggen, kann ich ihn sehr gerne mal posten, ich denke aber, da sind evtl so versteckte Fehler drin, dass es auch verwirren könnte.


    Besser wäre es sicher, mit etwas anzufangen, das jemand anderes geschrieben hat und das wirklich funktioniert.

  4. #4
    Erfahrener Benutzer Robotik Einstein
    Registriert seit
    18.03.2018
    Beiträge
    2.650
    Zu Arduino kann ich nichts beitragen, aber HTML-Formulare sind nicht schwer: https://wiki.selfhtml.org/wiki/HTML/...Webformular%3F

  5. #5
    HaWe
    Gast
    Zitat Zitat von Moppi Beitrag anzeigen
    Zu Arduino kann ich nichts beitragen, aber HTML-Formulare sind nicht schwer: https://wiki.selfhtml.org/wiki/HTML/...Webformular%3F
    Grundsätzlich ist das ja auch nicht das Problem, sondern die Arduino-mäßige Umsetzung. Aber ich mache es gerne mal konkret: Was ist an diesem Code fehlerhaft, dass er nicht mit ESP8266 cores 4.4.1 und 4.4.2 läuft sondern nur mit cores 4.3.0 und 4.4.0?

    Code:
    #include <ESP8266WiFi.h>
    #include <ESP8266WebServer.h>
    
    WiFiServer   wifiserver(http_port);
    const int  MAXLEN = 1024;
    const int  TOKLEN =  64;
    char  website_uname[20]; //  website user name log in  "MyWebsiteLoginName"
    char  website_upwd[20];  //  website user pwd log in   "MyWebsiteLoginPwd"
    
    bool authorized = false;
    
    void handleNotAuthorized() {
      String readString="";
      char   strinput[MAXLEN], strupwd[TOKLEN], struname[TOKLEN];
    
      WiFiClient client = wifiserver.available();
    
      //---------------------------------------
      // debug
      // authorized=true;
      
      strcpy(strinput, "");
      strcpy(strupwd, "");
      strcpy(struname, "");
    
      while ( client.connected() ) {
        if (authorized) return;
        
        readString.toCharArray(strinput, MAXLEN);
        // cstringarg( char* haystack, char* vname, char* sarg )
        // haystack pattern: &varname=1234abc,  delimiters &, \n, \0, SPACE, EOF
        cstringarg(strinput, "uname", struname);  // uname
        cstringarg(strinput, "upwd", strupwd);   // upwd    
    
        if ( strlen(strupwd) == strlen(website_upwd)
             && strncmp(strupwd, website_upwd, strlen(website_upwd) ) == 0)   {
          authorized = true;
          //debug
          //Serial.print("check: authorized="); Serial.println(authorized);
          readString = "";
          return;
        }
    
        if ( client.available() ) {
          char c = client.read();
    
          //read char by request
          if (readString.length() < TOKLEN) {
    
            //store characters to string
            readString += c;
            //Serial.print(c);
          }
    
          //if HTTP request has ended
          if (c == '\n') {
            client.flush();
            Serial.println(readString);
    
            //now output html data header
    
            String script = "";
    
            script += ("HTTP/1.1 401 Log-In Required");
            script += ("Content-Type: text/html \n");
            script += ("\n");   
            script += ("<!DOCTYPE html> \n");
            script += ("<html> \n");
            script += ("<head> \n");
    
    
            // utf-8 für "°" Zeichen
            script +=  "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"> \n" ;
            script +=  "<title>" ;
            script +=  website_title ;
            script +=  "</title> \n" ;
            script +=  "</head> \n" ;
            script +=  "<body> \n" ;
    
            script += "<h1><p style=\"color:rgb(255,0,191);\"> " + (String)website_url ;
            script += (String)": &nbsp; <wbr> <wbr> " + "Not authorized !</p> </h1> \n" ;
            script += ("<h2><p style=\"color:rgb(255,0,191);\"> log in to proceed: </p> </h2> \n");
    
            script += ("<FORM ACTION='/' method=GET > \n");
            script += ("<h2>user name:  <INPUT TYPE=text NAME='uname' VALUE=''  MAXLENGTH='50'> </h2> \n");
            script += ("<h2>password :  <INPUT TYPE=PASSWORD NAME='upwd' VALUE='' MAXLENGTH='50'> </h2> \n");
    
            script += ("<h2><INPUT TYPE=SUBMIT></h2> \n");
    
            script += ("</FORM> \n");
            script += ("<BR> \n");
            script += ("</body> \n");
            script += ("</html> \n");
    
            client.print(script);
    
            //stopping client
            client.stop();
            delay(1);
    
            //clearing string for next read
            readString = "";
          }
        }
        delay(1);
      }
    }
    Bei den beiden neueren Cores springt er zur Laufzeit sofort aus dieser Funktion heraus und bricht ab mit der Meldung "Die Website ist nicht verfügbar", und dann kann man sich auch nicht erneut einloggen oder die Standard-Website aufrufen.
    Ansonsten wird bei den älteren Cores bei korrektem Login auch anschließend die Standard-Seite korrekt geladen.
    Setzt man authorized dagegen vorher manuell auf true, wird bei jedem Core, neu wie alt, auch sofort die Standardseite korrekt erzeugt.

    oder sind es evt bugs in den esp-cores selber?
    Geändert von HaWe (12.08.2018 um 13:37 Uhr)

  6. #6
    Erfahrener Benutzer Robotik Einstein
    Registriert seit
    18.03.2018
    Beiträge
    2.650
    Bei PHP änderten sich mal die Variablen, weswegen ältere Scripte auf neuen Versionen nicht funktionierten. Man musste nur die Variablennamen ändern. Es könnte sich auch die Zugriffsart oder die Methode ändern - eine Funktion wurde geändert oder durch eine andere ersetzt. Syntax wurde irgendwo geändert, Funktion erwartet mehr oder erwartet weniger Parameter als vorher und stürzt ab, bzw. erzeugt Fehler.
    Kannst Du eine Rückmeldung erzeugen im Script? Sowas wie alert() in Javascript? Irgendwas, was man vor jeder Codezeile einbaut und dann sieht man, wo was hängt - wenn ich vom Absturz ausgehe. Ein Debuger ist natürlich besser. Irgendwie muss man die Fehlerquelle einkreisen und sich dann mit dem was übrig bleibt im Detail beschäftigen. Oder man muss die Befehle überprüfen, ob die alle auf "den beiden neueren Cores" auch so nach außen implementiert sind, wie auf den "alten" - ob es dort irgendwo an einer Stelle Änderungen gab. Es sollte Befehlslisten mit Beschreibung geben. An sich ist nichts Schweres dran am Code. Bloß ich habe damit noch nie gearbeitet. Deshalb meinerseits notdürftige Denkanstöße und hier keine Gewähr auf irgendeine Richtigkeit.

    Man kann auch handleNotAuthorized() neu aufbauen. Erst mal alles raus nehmen und dann Codezeile um Codezeile hinzufügen. Nur man braucht eine Rückmeldung, damit man feststellen kann ab wann es nicht mehr funktioniert.


    Nachtrag:

    Compilerversion und Bibliotheken passen auch zu den "neuen Cores"?
    Geändert von Moppi (12.08.2018 um 15:37 Uhr)

  7. #7
    HaWe
    Gast
    Zitat Zitat von Moppi Beitrag anzeigen
    Bei PHP änderten sich mal die Variablen, weswegen ältere Scripte auf neuen Versionen nicht funktionierten. Man musste nur die Variablennamen ändern. Es könnte sich auch die Zugriffsart oder die Methode ändern - eine Funktion wurde geändert oder durch eine andere ersetzt. Syntax wurde irgendwo geändert, Funktion erwartet mehr oder erwartet weniger Parameter als vorher und stürzt ab, bzw. erzeugt Fehler.
    Kannst Du eine Rückmeldung erzeugen im Script? Sowas wie alert() in Javascript? Irgendwas, was man vor jeder Codezeile einbaut und dann sieht man, wo was hängt - wenn ich vom Absturz ausgehe. Ein Debuger ist natürlich besser. Irgendwie muss man die Fehlerquelle einkreisen und sich dann mit dem was übrig bleibt im Detail beschäftigen. Oder man muss die Befehle überprüfen, ob die alle auf "den beiden neueren Cores" auch so nach außen implementiert sind, wie auf den "alten" - ob es dort irgendwo an einer Stelle Änderungen gab. Es sollte Befehlslisten mit Beschreibung geben. An sich ist nichts Schweres dran am Code. Bloß ich habe damit noch nie gearbeitet. Deshalb meinerseits notdürftige Denkanstöße und hier keine Gewähr auf irgendeine Richtigkeit.

    Man kann auch handleNotAuthorized() neu aufbauen. Erst mal alles raus nehmen und dann Codezeile um Codezeile hinzufügen. Nur man braucht eine Rückmeldung, damit man feststellen kann ab wann es nicht mehr funktioniert.
    nein, leider kenne ich mich mit all dem nicht aus.
    Alles was ich habe ist obiger Code, der nicht bei den neuen cores funktioniert und den ein fähiger Programmierer debuggen können müsste, ansonsten bitte lieber auch gerne einen alternativen, lauffähigen eigenen Code, den ich direkt in die Arduino IDE c+p'en kann.

  8. #8
    HaWe
    Gast
    updae:
    ich habe jetzt einen Code zusammengebastelt, der einigermaßen, aber noch nicht 100%ig funktioniert.
    Fürs erste teste ich nur aufs Passwort wegen der Debug-Phase.
    ist es völlig falsch, wird es zurückgewiesen, ist es 100% richtig, dann auch angenommen.

    Problem aber:
    wenn das Pwd zB "12345" ist, und der usr gibt "1234567" ein, wird es auch akzeptiert. Ich kriege nicht raus, wo der Fehler liegt.
    Wer weiß wo der Hase im Pfeffer liegt?

    Hier erst mal 2 Hilfsfunktionen, um Passwort etc. aus dem html-String rauszufischen (funktioniert ansonsten einwandfrei):

    Code:
    int16_t  strstrpos(char * haystack,  char * needle)   // find 1st occurance of substr in str
    {
       char *p = strstr(haystack, needle);
       if (p) return p - haystack;
       return -1;   // Not found = -1.
    }
    
    //----------------------------------------------------------------------------
    const int  MAXLEN = 1024;
    const int  TOKLEN = 64;
    
    char * cstringarg( char* haystack, char* vname, char* sarg ) {
       int i=0, pos=-1;
       unsigned char  ch=0xff;
       char  kini[3] = "&";       // start of varname: '&': 
       char  kequ[3] = "=";       // end of varname, start of argument: '='
       char  needle[TOKLEN]="";   // complete pattern:  &varname=abc1234
    
       //kequ[0] = '=';  // customize
       strcpy(sarg,"");
       strcpy(needle, kini);
       strcat(needle, vname);
       strcat(needle, kequ);
       pos = strstrpos(haystack, needle); 
       if(pos==-1) return sarg;
       pos=pos+strlen(vname)+2; // start of value = kini+vname+kequ   
       while( (ch!='&')&&(ch!='\0') ) {
          ch=haystack[pos+i];    
          if( (ch=='&')||(ch==';')||(ch==' ')||(ch=='\0') ||(ch=='\n')
            ||(i+pos>=strlen(haystack))||(i>TOKLEN-1) ) {
               sarg[i]='\0';
               return sarg;
          }       
          if( (ch!='&') ) {
              sarg[i]=ch;          
              i++;       
          }      
       } 
       return sarg;
    }
    und hier jetzt die eigentliche Website, die username und passwort anfordert zum Login:

    Code:
    char  website_uname[20]="abcde"; //  website user name 
    char  website_upwd[20]="12345"; // website user pwd 
    
    void handleNotAuthorized() {
      String readString="";
      char   strinput[MAXLEN], strupwd[TOKLEN], struname[TOKLEN];
    
      WiFiClient client = wifiserver.available();
    
      //---------------------------------------
    
      strcpy(strinput, "");
      strcpy(strupwd, "");
      strcpy(struname, "");
    
      while ( client.connected() ) {
        if (authorized) return;
        
        readString.toCharArray(strinput, MAXLEN);
    
        // cstringarg( char* haystack, char* vname, char* sarg )
        // haystack pattern: &varname=1234abc,  delimiters &, \n, \0, SPACE, EOF
        cstringarg(strinput, "uname", struname);  // uname
        cstringarg(strinput, "upwd", strupwd);   // upwd    
    
        if ( strlen(strupwd) == strlen(website_upwd)
             && strcmp(strupwd, website_upwd ) == 0)   {
          authorized = true;
          readString = "";
          return;
        }
    
        if ( client.available() ) {
          char c = client.read();
    
          //read char by request
          if (readString.length() < TOKLEN) {
    
            //store characters to string
            readString += c;
            //Serial.print(c);
          }
    
          //if HTTP request has ended
          if (c == '\n') {
            client.flush();
            Serial.println(readString);
    
            //now output html data header
    
            String script = "";
    
            script += ("HTTP/1.1 401 Log-In Required");
            script += ("Content-Type: text/html \n");
            script += ("\n");  //  do not forget this one //????
            script += ("<!DOCTYPE html> \n");
            script += ("<html> \n");
            script += ("<head> \n");
    
    
            // utf-8 für "°" Zeichen
            script +=  "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"> \n" ;
            script +=  "<title>" ;
            script +=  website_title ;
            script +=  "</title> \n" ;
            script +=  "</head> \n" ;
            script +=  "<body> \n" ;
    
            script += "<h1><p style=\"color:rgb(255,0,191);\"> " + (String)website_url ;
            script += (String)": &nbsp; <wbr> <wbr> " + "Not authorized !</p> </h1> \n" ;
            script += ("<h2><p style=\"color:rgb(255,0,191);\"> log in to proceed: </p> </h2> \n");
    
            script += ("<FORM ACTION='/' method=GET > \n");
            script += ("<h2>user name:  <INPUT TYPE=text NAME='uname' VALUE=''  MAXLENGTH='50'> </h2> \n");
            script += ("<h2>password :  <INPUT TYPE=PASSWORD NAME='upwd' VALUE='' MAXLENGTH='50'> </h2> \n");
    
            script += ("<h2><INPUT TYPE=SUBMIT></h2> \n");
    
            script += ("</FORM> \n");
            script += ("<BR> \n");
            script += ("</body> \n");
            script += ("</html> \n");
    
            client.print(script);
    
            //stopping client
            client.stop();
            delay(1);
    
            //clearing string for next read
            readString = "";
          }
        }
        delay(1);
      }
    }

  9. #9
    Erfahrener Benutzer Robotik Einstein
    Registriert seit
    18.03.2018
    Beiträge
    2.650
    Das if() funktioniert:

    Code:
    if (strlen(strupwd) == strlen(website_upwd)
             && strcmp(strupwd, website_upwd ) == 0) .....
    Wenn die Eingangsstrings korrekt sind. Also 12456 und 1234567, wird korrekt als falsch erkannt, sowie 123456 und 123456 als richtig.
    Also musst Du davor nach dem Problem suchen.

    Ich tippe hier auf das Problem, habe ich noch nicht richtig angeschaut:

    Code:
    cstringarg(strinput, "upwd", strupwd);   // upwd

  10. #10
    HaWe
    Gast
    Zitat Zitat von Moppi Beitrag anzeigen
    Das if() funktioniert:

    Code:
    if (strlen(strupwd) == strlen(website_upwd)
             && strcmp(strupwd, website_upwd ) == 0) .....
    Wenn die Eingangsstrings korrekt sind. Also 12456 und 1234567, wird korrekt als falsch erkannt, sowie 123456 und 123456 als richtig.
    Also musst Du davor nach dem Problem suchen.

    Ich tippe hier auf das Problem, habe ich noch nicht richtig angeschaut:

    Code:
    cstringarg(strinput, "upwd", strupwd);   // upwd
    hallo,
    das cstringarg habe ich als isolierte Funktion mit mehreren Teststrings geprüft, es hat immer den richtigen arg-Teilstring zurückgegeben, aber ich kann tatsächlich nicht ausschleißen, dass nicht doch irgendein verdeckter Bug drin steckt.
    Du hast ja auch völlig Recht, die Abfrage
    if (strlen(strupwd) == strlen(website_upwd)
    müsste diesen Fehler 12345 != 1234567 heraussieben.
    Die Ungleichheit "1245" != "12345" etc wird ja hingegen korrekt erkannt., und die Gleichheit "12345" == "12345" ebenfalls.

    Es sei denn die Länge wird nicht richtig ermittelt, z.B. wegen fehlender '\0' in den beiden cstrings (wofür ich allerdings auch keinen Anhaltspunkt habe),
    oder die Funktion macht bereits einen Vergleich auf Identität, ohne dass bereits "Enter" gedrückt wurde, und überspringt dabei die folgenden Eingaben - doch auch dafür sehe ich keinen Anlass.

    Es ist mir ein absolutes Rätsel.

    - - - Aktualisiert - - -



    update:
    hier ein testcode für cstringarg(), und er funktioniert bestens, sowohl mit direkt aneinanderhängenden als auch bei durch (fälschlich) mit Leerzeichen getrennten Teilstrings:

    Code:
    int16_t  strstrpos(char * haystack,  char * needle)   // find 1st occurance of substr in str
    {
       char *p = strstr(haystack, needle);
       if (p) return p - haystack;
       return -1;   // Not found = -1.
    }
    
    //----------------------------------------------------------------------------
    const int  MAXLEN = 1024;
    const int  TOKLEN = 64;
    
    char * cstringarg( char* haystack, char* vname, char* sarg ) {
       int i=0, pos=-1;
       unsigned char  ch=0xff;
       char  kini[3] = "&";       // start of varname: '&': 
       char  kequ[3] = "=";       // end of varname, start of argument: '='
       char  needle[TOKLEN]="";   // complete pattern:  &varname=abc1234
    
       //kequ[0] = '=';  // customize
       strcpy(sarg,"");
       strcpy(needle, kini);
       strcat(needle, vname);
       strcat(needle, kequ);
       pos = strstrpos(haystack, needle); 
       if(pos==-1) return sarg;
       pos=pos+strlen(vname)+2; // start of value = kini+vname+kequ   
       while( (ch!='&')&&(ch!='\0') ) {
          ch=haystack[pos+i];    
          if( (ch=='&')||(ch==';')||(ch==' ')||(ch=='\0') ||(ch=='\n')
            ||(i+pos>=strlen(haystack))||(i>TOKLEN-1) ) {
               sarg[i]='\0';
               return sarg;
          }       
          if( (ch!='&') ) {
              sarg[i]=ch;          
              i++;       
          }      
       } 
       return sarg;
    }
    
    void setup() {
      Serial.begin(115200);
      Serial.println();
      Serial.println("Test mit cstringarg()");
      Serial.println();
      
      char htmlstring[1024]="html teststring mit und ohne Leerzeichen &upwd1=testupwd1&upwd2=testupwd2 &upwd13=testupwd13&upwd224=testupwd224 EndeTststring";
      char argstring[64]="";
    
      cstringarg(htmlstring, "upwd1", argstring);
      Serial.print("upwd1 >>"); Serial.print(argstring); Serial.println("<< soll: >>testupwd1<<");
    
      cstringarg(htmlstring, "upwd2", argstring);
      Serial.print("upwd2 >>"); Serial.print(argstring); Serial.println("<< soll: >>testupwd2<<");
      
      cstringarg(htmlstring, "upwd13", argstring);
      Serial.print("upwd13 >>"); Serial.print(argstring); Serial.println("<< soll: >>testupwd13<<");
    
      cstringarg(htmlstring, "upwd224", argstring);
      Serial.print("upwd224 >>"); Serial.print(argstring); Serial.println("<< soll: >>testupwd224<<"); 
       
    }
    
    void loop() {
      
    }
    das einzige, was ich vermuten würde, wäre daher etwas in der "Logik", wie die html-Seite aufgebaut ist und wie ihr html string mit dem Text der Eingabefelder zusammengesetzt, gesendet und ausgewertet wird.

Seite 1 von 4 123 ... LetzteLetzte

Ähnliche Themen

  1. html-Code für nodeMCU mit Arduino IDE + Wifi libs
    Von HaWe im Forum Arduino -Plattform
    Antworten: 7
    Letzter Beitrag: 14.08.2018, 19:30
  2. Pegelwandler RX/TX Arduino ESP8266
    Von Cysign im Forum Elektronik
    Antworten: 3
    Letzter Beitrag: 06.02.2018, 00:29
  3. ESP8266 boards per per Arduino-IDE programmieren?
    Von HaWe im Forum Arduino -Plattform
    Antworten: 27
    Letzter Beitrag: 10.06.2017, 16:19
  4. arduino ide mit esp8266
    Von NotEvil im Forum NodeMCU-Board und ESP8266, ESP32-Serie
    Antworten: 4
    Letzter Beitrag: 12.01.2017, 15:17
  5. HTML-Code (scripts)
    Von Technik =) im Forum Umfragen
    Antworten: 6
    Letzter Beitrag: 10.10.2008, 10:21

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •  

fchao-Sinus-Wechselrichter AliExpress