Kirjautuminen

Haku

Tehtävät

Keskustelu: Nettisivujen teko: [PHP] IRC Bot ja vaaditut parametrit

Sivun loppuun

kayttaja-12357 [06.07.2013 21:42:04]

#

Terve,

eli PHP IRC Bottia olen kehittelemässä ja aika uusi tälle PHP kielellekkin olen. Eli ongelma on tällainen: olen luomaassa "!MD5" komentoa, jotta voisin muuttaa annetun tekstin MD5 muotoon. Ongelma on se, että en saa tuota millään pelaamaan, kun komennon syntaksi on "!MD5 <text>". Eli, jos käyttäjä kirjoittaa vain "!MD5" chattiin, haluaisin sen antavan syntaksin käyttäjälle ja jos parametrit on kirjoitettu, se kääntää annetun tekstin MD5 muotoon.

if(stripos($data, '!md5')) {
        			$params = '';
					$a = explode(' ', $params);
        			if(isset($params[1])) {
        				fputs($this->socket, "PRIVMSG #Kanava :".md5($params)." \r\n");
        			} else {
        				fputs($this->socket, "PRIVMSG #Kanava :Error. Syntax: !MD5 <text> \r\n");
        			}
        		}

Tuossa koodissa menee jokin pieleen. Olen yrittänyt käännellä, väännelllä ja säädellä sitä ilman mitään tulosta. Huomaan, että PHP eroaa C ja PAWN kielestä.

Olisi myös todella mukava myös tietää, miten saat käyttäjän, joka suoritti komennon ja hänen modin (esimerkiksi +o ja ne).

Kiitos vastauksesta jo etukäteen!

reino [07.07.2013 11:46:39]

#

Koodissasi et aseta muuttujalle $params oikeaa arvoa. Lisäksi asetat muuttujan $a, mutta käytät silti if lauseessa $params muuttujaa.

Tällainen koodi voisi toimia:

if(stripos($data, '!md5')) {
					$a = explode(' ', $params);
        			if(isset($a[1])) {
        				fputs($this->socket, "PRIVMSG #Kanava :".md5($params)." \r\n");
        			} else {
        				fputs($this->socket, "PRIVMSG #Kanava :Error. Syntax: !MD5 <text> \r\n");
        			}
        		}

EDIT: Koodia korjattu

The Alchemist [07.07.2013 11:53:11]

#

Heikkoa. Stripos() palauttaa kokonaisluvun, joka kertoo merkkijonon B sijainnin toisessa merkkijonossa A.

kayttaja-12357 [07.07.2013 15:46:31]

#

@ reino: Tuo koodi ei toiminut. Antaa "Undefined variable: "params"". Kun komenossa on annettu kaikki tarvittavat merkkijonot, valittaa vieläkin tota "Syntaksia".

@ The Alchemist: Mikä olisi parempi vaihto ehto, mikä ei ole case sensitive? Mitens olisi "strcmp"?

Kiitos vastauksesta jo etukäteen!

EDIT: replyä muokattu.

Grez [07.07.2013 17:18:18]

#

Käsittääkseni stripos palauttaa kokonaisluvun JOS merkkijono sijaitsee toisessa merkkijonossa ja false JOS se ei sisällä sitä.

Eli nythän tuo if-lauseen sisältöä ei ajeta, mikäli !md5 löytyy heti merkkijonon alusta (sijainti 0 joka tulkitaan tuossa vertailussa epätodeksi)

Käytännössä siis (ellei nimenomaan haluta ettei alussa olevaa huomioida) tulisi varmaankin kirjoittaa

if(stripos($data, '!md5')!==false)

En sit tiedä tarkoittiko Alchemist vielä jotain muuta. En hirveesti PHP:llä koodaa, mutta sieltä ei taida löytyä "contains" -tyylistä funktiota, joka toki olisi tyylikkäämpi vaihtoehto.

kayttaja-12357 [07.07.2013 17:31:15]

#

Grez kirjoitti:

Käytännössä siis (ellei nimenomaan haluta ettei alussa olevaa huomioida) tulisi varmaankin kirjoittaa

if(stripos($data, '!md5')!==false)

Valitettavasti tuokaan ei auttanut, mutta kiitos silti.

if(stripos($data, "!md5") !== false) {
					$a = explode(' ', $params);
        			if(isset($a[1])) {
        				fputs($this->socket, "PRIVMSG #Kanava :".md5($params)." \r\n");
        			} else {
        				fputs($this->socket, "PRIVMSG #Kanava :Error. Syntax: !MD5 <text> \r\n");
        			}

Sanoo edelleen, että "Undefined variable: "params"". Ja kun syötän komennon täydellisesti, antaa edelleen syntaksia minulle.

Olisiko mahdollisesti $data muuttujalle jotain tehtävissä?

Näyttää tälläiselta:

// Fetch data from server:
while($data = fgets($this->socket, 256)) {
}

Tuon koodin sisällä sijaitsee ping pong ja komennot.

Kiitos vastauksesta jo etukäteen.

Grez [07.07.2013 17:45:05]

#

No missä sit määrittelet sen muuttujan $params ?

Ei tollaisesta osittaisesta koodista pysty löytämään virheitä jotka ei sisälly näytillä olevaan koodiin.

kayttaja-12357 [07.07.2013 18:14:20]

#

$params muuttujaa ei ole missään muualla kuin tuossa. Tuo on "reinon" muokkaamaa koodia, mutta yritin lisätä sen false tarkistuksen siihen. Kysyisin, miten voin määritellä tuon toisen tarvittavan merkkijonon oikein? Tuntuu, että muuttujat eroaa aika paljon C/PAWN kielestä.

Tiedän kyllä mitä ne muuttujat on, mutta tämä lienee olevan erilainen tapaus, kuin normaalisti?

Metabolix [07.07.2013 18:26:26]

#

Et kai missään C/PAWN-kielessäkään (mikä ihme se on?) saa tyhjästä taiottua muuttujaa $params. Jos parametrit ovat $data-muuttujassa !MD5-komennon perässä, sinun pitää jotenkin poimia ne sieltä – vaikkapa katkomalla merkkijono explode-funktiolla tai vielä mieluummin poimimalla siitä osa substr-funktiolla.

$data = "!MD5 moi"; // Tämä kai tulee jostain?
$osat = explode(" ", $data, 2);
$parametri = $osat[1];
$tulos = md5($parametri);

Grezin antama tarkistus taas tunnistaa tekstin ”!MD5” mistä tahansa kohdasta $data-muuttujaa, jolloin esimerkiksi "heppa!md5" menee läpi. Jos haluat tarkistaa, että teksti on nimenomaan $data-muuttujan alussa, oikeita tapoja ovat mm. seuraavat:

if (stripos($data, "!MD5") === 0) { ... }
if (strcasecmp(substr($data, 0, 4), "!MD5") === 0) { ... }

Viisainta olisi, että ensiksi tunnistaisit $data-muuttujan alusta IRC-protokollaan liittyvät asiat ja poistaisit ne ja sen jälkeen vasta tunnistaisit komennon tällä tavalla.

kayttaja-12357 kirjoitti:

Tiedän kyllä mitä ne muuttujat on, mutta tämä lienee olevan erilainen tapaus, kuin normaalisti?

Mitä? :D Ei tämä ole mitenkään ”erilainen tapaus”. Ohjelmoinnissa ei juurikaan ole mitään ”erilaisia tapauksia”, vaan säännöt ovat sääntöjä.

Oletko harkinnut PHP-oppaan lukemista?

Grez [07.07.2013 19:06:57]

#

No juu kommentoin lähinnä tota striposia yleisesti sillä oletuksella että haluttiin vaan tietää sisältääkö merkkijono a merkkijonon b. Mutta tietty vois lukea koko koodinkin ennen kuin kommentoi.

kayttaja-12357 [07.07.2013 19:37:50]

#

@ Metabolix: Esimerkiksi PAWN kielessä ussi variable on vain "new something;" ja parametrina, eli arrayna "new something[64];". Läninnä tuolla tarkoita, että eroaa.

EDIT: Okei. tilanne on nyt sellainen, että tuo "stripos" ja "strcasecmp" yhdistettynä ei tee mitään (mitään ei tapahdu, kun kirjoittaa "!MD5"). Ja nyt kun kirjoita "!MD5" se ottaa sen suoraan, ilman antamatta syntaxia.

$string = explode(" ", $data, 2);
        			$parameters = $string[1];
        			if(isset($parameters)) {
        				fputs($this->socket, "PRIVMSG #Kanava :".md5($parameters)." \r\n");
        			} else {
        				fputs($this->socket, "PRIVMSG #Kanava :Error. Syntax: !MD5 <text> \r\n");
        			}

Se ilmeisesti muuntaa jo tuon !MD5 tekstin suoraan MD5 muotoon. Kiitos vielä kaikille, ja olisi kiva jos vielä tämä saataisiin korjattua!

kayttaja-12357 [09.07.2013 12:55:48]

#

Bump up. Eli tuo Metabolixin vinkki stripoksesta ja substringistä ei tominunut. Botti ei havaitse komentoa. Joku kehotti käytämään tuota "explode" funktiota tunnistaaksesi, milloin tule ":" merkki "PRIVMSG" raw function jälkeen, jolloin botti pystyisi tunnistamaan komennon, kun joku puhuu kanavassa.

Olisi myös kiva nähdä, mitten se tunnistaisi, jost ei kirjoita toista merkkijonoa, koska sekään ei toimi. Ei anna syntaksia, kun kirjoittaa vain "!MD5".

Kiitos vastauksesta jo etukäteen!

The Alchemist [09.07.2013 13:31:41]

#

Grez kirjoitti:

En sit tiedä tarkoittiko Alchemist vielä jotain muuta. En hirveesti PHP:llä koodaa, mutta sieltä ei taida löytyä "contains" -tyylistä funktiota, joka toki olisi tyylikkäämpi vaihtoehto.

Kommentoin seuraavanlaista koodia:

if (($params = stripos($data, '!md5'))) {
    $a = explode(' ', $params);
    ...
}

Ruma tapa muokata koodiesimerkkejä salaa jälkikäteen, olivatpa ne miten tyhmiä tahansa.

hunajavohveli [10.07.2013 16:30:21]

#

kayttaja-12357 kirjoitti:

Näyttää tälläiselta:

// Fetch data from server:
while($data = fgets($this->socket, 256)) {
}

Tässä on pari virhettä. Ensinnäkin yhden IRC-viestin pituus voi olla enintään 512 tavua ja toiseksi fgets voinee ainakin teoriassa lukea myös pätkän viestiä, jota ei ole vielä lähetetty kokonaan?

Edit: Kannattaa tosiaan ensin jäsentää se IRC-viesti ja erotella siitä prefiksi, komento sekä varsinainen viestiosuus. Tämän jälkeen annettujen esimerkkien pitäisi toimia viestiosuudelle.

groovyb [10.07.2013 17:17:26]

#

Eikös sen saisi tähän tyyliin:

var $ex = array();
$ex = explode(' ', $data);

$command = str_replace(array(chr(10), chr(13)), '', $ex[3]);

switch($command)
{
	case ':!md5':
		var $hash = $this->ConvertToMD5($ex[4]);
		$this->Send($hash);
		break;
}

kayttaja-12357 [10.07.2013 19:16:36]

#

groovyb kirjoitti:

Eikös sen saisi tähän tyyliin:

var $ex = array();
$ex = explode(' ', $data);

$command = str_replace(array(chr(10), chr(13)), '', $ex[3]);

switch($command)
{
	case ':!md5':
		var $hash = $this->ConvertToMD5($ex[4]);
		$this->Send($hash);
		break;
}

Tuolla ei sitten saa edelleekään annettua syntaksia, jos käyttäjä typettää vain "!MD5" ja tuo ei taida olla case-insensitive, vai onko se? Olisi myös todella kiva tietää, miten saisit käyttäjän modet kanavalla?

Kiitos, ja olisin edelleen sitä mieltä, että "stripos" tai vastaavalla voisi yrittää.

groovyb [10.07.2013 19:24:34]

#

no käytä inputissa https://www.php.net/manual/en/function.strtolower.php, ja kyllä, tuo osaa parsia jos joku kirjoittaa !MD5.

Lisää tuohon switchin sisään mahdolliset muut bottikomennot.

kayttaja-12357 [10.07.2013 19:51:48]

#

groovyb kirjoitti:

no käytä inputissa https://www.php.net/manual/en/function.strtolower.php, ja kyllä, tuo osaa parsia jos joku kirjoittaa !MD5.

Lisää tuohon switchin sisään mahdolliset muut bottikomennot.

Ja kuinka kerrot käyttäjälle komennon syntaksin, jos se kirjoittaa vain "!MD5"? Olen edelleen stripoksen puolella, sillä vosin ehkä tunnistaa komentoja käyttäjän, käyttäjien puolesta sillä on pieni projekti meneillään.

Voisin ehkä yrittää "The Alchemistin" neuvoa, muta parannetusti. Se on ehkä 3 tai 4 array, jolloin komento alkaa: "käyttäjä.host PRIVMSG #Kanava :!MD5 <params>..." luulisin. Sitten explodella voisi tehä sen ^.

groovyb [10.07.2013 19:57:43]

#

tsekkaas tämä läpi noin niinkuin yleisesti:
http://www.dreamincode.net/forums/topic/82278-creating-an-irc-bot-in-php/

no mikäli $ex[4] on tyhjä, tarkoittaa se että käyttäjä ei ole mitään merkkijonoa !MD5:sen perään lisännyt. mikäli $ex[4] on null, lähetetään käyttäjälle ohjeet PRIVMSG:nä.

kayttaja-12357 [10.07.2013 20:11:47]

#

Okay. Muistaakseni tuo dream ingin PHP Bot antaa varoituksia siinä "$command =..." jutussa ja pystyykä tuolla tunnistamaan komentoja miltään muulta etäisyydeltä niinkuin stripoksella?

Joka tapauksessa aijon yrittää stripoksella, ei ainakaan anna varoituksia.

Miten saat käyttäjien user modet tietyllä kanavalla? Ei löydy siitä mitään materiaaalia.

groovyb [10.07.2013 20:19:51]

#

IRC Standard kirjoitti:

3.2.5 Names message

Command: NAMES

Parameters: [ <channel> *( "," <channel> ) [ <target> ] ]

By using the NAMES command, a user can list all nicknames that are visible to him. For more details on what is visible and what is not, see "Internet Relay Chat: Channel Management" [IRC-CHAN]. The <channel> parameter specifies which channel(s) to return information about. There is no error reply for bad channel names.

If no <channel> parameter is given, a list of all channels and their occupants is returned. At the end of this list, a list of users who are visible but either not on any channel or not on a visible channel are listed as being on 'channel' "*".

If the <target> parameter is specified, the request is forwarded to that server which will generate the reply.

Wildcards are allowed in the <target> parameter.

Numerics:

ERR_TOOMANYMATCHES ERR_NOSUCHSERVER
RPL_NAMREPLY RPL_ENDOFNAMES

Examples:

NAMES #twilight_zone,#42 ; Command to list visible users on #twilight_zone and #42

NAMES ; Command to list all visible channels and users

Quering a channel with the NAMES command will yield these two replies:


353 RPL_NAMREPLY

"( "=" / "*" / "@" ) <channel>
:[ "@" / "+" ] <nick> *( " " [ "@" / "+" ] <nick> )
•"@" is used for secret channels, "*" for private channels, and "=" for others (public channels).

as well as:


366 RPL_ENDOFNAMES

"<channel> :End of NAMES list"

You can split the list of nicks on the whitespace character, and determine whether the first character of a nick is a mode identifier (+, @, etc..) or an alphanumeric character (which implies that the user has no special mode on the channel.)

The IRC standard only defines + as a voiced user and @ as a channel operator, but other servers can be known to use special characters like ~ for channel owner and & for "super" channel operators. As a general rule, you could simply check to see that the user has any channel mode (other than the default) to verify that they're voiced or better.

The Alchemist [11.07.2013 08:52:21]

#

kayttaja-12357 kirjoitti:

Okay. Muistaakseni tuo dream ingin PHP Bot antaa varoituksia siinä "$command =..." jutussa ja pystyykä tuolla tunnistamaan komentoja miltään muulta etäisyydeltä niinkuin stripoksella?

Joka tapauksessa aijon yrittää stripoksella, ei ainakaan anna varoituksia.

Miten saat käyttäjien user modet tietyllä kanavalla? Ei löydy siitä mitään materiaaalia.

Et voi tunnistaa komentoja striposia käyttäen alkuperäisestä syötteestä. Muutenkin se on helvetin tyhmää. Ainoa järkevä tapa on ensin parsia rivistä eri osat erilleen ja sen jälkeen vasta aloittaa komentojen tulkkaus.

Matti Kaijomaa [11.07.2013 10:12:22]

#

Tästä ketjusta huomaa, ettei aloittaja juurikaan hallitse ohjelmoinnissa tarvittavaa peruslogiikkaa: muuttujien oletetaan ilmestyvän tyhjästä ja annetuista vinkeistä ei saada muuta irti kuin yksinkertaisia leikkaa ja liimaa -korjausyrityksiä. Ystävällisesti kysynkin, onko aivan pakollista tehdä heti alkuun IRC-botti. Valmiin koodin muokkaaminen omiin tarkoituksiin vaatii vähän harjaantuneempaa silmää, jotta projekti pysyisi kasassa, ja lisäksi pelkän ohjelmointikielen lisäksi joudut opettelemaan IRC:n protokollan. Yksinkertaisemman projektin (sellaisen, jonka koodia itsekin ymmärrät) parissa kehittyisit varmasti paremmin.

hunajavohveli [11.07.2013 15:03:04]

#

Ei kannata luottaa siihen, että viestiparametri alkaa kaksoispisteellä. Oman kokemukseni mukaan palvelimet tyypillisesti lisäävät sen, mutta RFC:n mukaan sitä ei vaadita, ellei viesti sisällä välilyöntejä (tai kaksoispistettä). Muutenkin on loogisinta ensin parsia parametrilista sellaisenaan ja jakaa viestiparametri osiin vasta erikseen, jos tarve vaatii.

kayttaja-12357 [23.07.2013 10:05:43]

#

Terve,

Eli nyt olen yrittänyt tällaista ja olen omasta mielestäni ymmärtänyt näitä asioita jotenkin oikein, mutta vieläkään ei toimi. Alhaalla yritän selittää koodia:

$ex = explode(" ", $data); // Explodeaan, jotta olisi helpompi erottaa viesti palaset toisistaan.

// Plays PING and PONG:
if($ex[0] == "PING") {
    fputs($socket, "PONG ".$ex[1]. "\r\n"); // Palvelin lähettaa botille aina silloin tällöin PING pyynnön, johon pitää vastata.
}

/*
Strcasecmp on case-insensitive. Kolmas array index on se missä viesti tulee. Konsoli näyttää, että se viesti alkaisi tuolla kaksoispisteellä. Jostain ihmeen syystä, tämä "$ex[3]" valittaa, että "Undefined offset 3". Botti ei edes tunnista koko komentoa alhaalla.
*/
if(strcasecmp($ex[3], ":!EXIT") == 0) {
     fputs($socket, "QUIT :PHPBot is CLOSING down! \r\n");
     fclose($socket);
     exit;
}

Muutin viestin pituuden 256:sta 512. Missä mahtaisi vieläkin olla vika?

Arvostan apua! Kiitos vastauksesta jo etukäteen!

feenix [23.07.2013 18:29:11]

#

Tarkoitatko kolmannella sitä, että siellä on "ASD DAS :!EXIT"? Jolloin tuo olisi indeksi 2 kun aloitetaan nollasta?

kayttaja-12357 [24.07.2013 17:49:54]

#

Terve!

Noniin, nyt sain toimimaan tuon "!EXIT" komennon yläpuolella strcasecmp:tä kayttäen. Tuo PHP Notice "Undefined offset 3" minun tapauksessani on bugi, tai ei ole. Sen voi kuulemma estää emptyä tai counttia käyttäen.

Mennään eteen päin. Nyt yritin kehitellä toista komentoa botille, joka vaatii kaksi parametriä. Yritin tehdä simppeliä "!REPEAT" komentoa, jolloin botin pitäisi toistaa mitä sanon. Ongelma on sellainen, kun kirjoittaa "!REPEAT" se antaa tuon syntaksin sille komennolle, mutta sitten kun kirjoittaa tekstiä, se ei sano sitä ulos. Botti ei myöskään anna syntaksia käyttäjälle, jos komennossa on välilyönti ("!REPEAT ").

Alhaalla on taas hieman koodia:

if(!empty($ex[3])) {
	if(strcasecmp($ex[3], ":!REPEAT\r\n") == 0) {
		if(!empty($ex[4]) || !is_null($ex[4])) {
			fputs($socket, "PRIVMSG #Kanava :" . $ex[4] . "\r\n");
		}
		else {
			fputs($socket, "PRIVMSG #Kanava :Error. Syntax: !REPEAT <text> \r\n");
		}
	}
}

Mikä on vikana? Myös kysyisin, antaako se tekstin ulos ilman noticeja tai erroreita jos laittaa välilyönnin ja teksti jatkuu siinä viidennellä array indexillä?

Kiitos!

feenix [25.07.2013 15:40:33]

#

Koska $ex[3] ei sisällä tietenkään rivinvaihtoa, jos sen perässä on vielä tekstiä. Älä tietenkään vertaile rivinvaihtoja sisältävään tekstiin vaan rivinvaihtomerkit pitäisi poistaa ennen vertailuja. Ne eivät kuulu komentoihin vaan protokollaan.

The Alchemist [25.07.2013 19:21:58]

#

Strcasecmp ei toimi, usko jo jumalauta. Yhtään kun miettisit asiaa itse, niin ymmärtäisit sen. Parsi viestiriveistä asiallisesti eri osat pihalle, jonka jälkeen voit helposti reagoida eri komentoihin asian mukaisesti.

Metabolix [26.07.2013 22:36:31]

#

Eräs ratkaisu tähänkin merkkijono-ongelmaan ovat säännölliset lausekkeet: niillä voit kerralla tunnistaa komennon ja kerätä sen parametrit taulukoksi.

Sivuhuomio: Älä yritä ”selventää” keskustelua muokkaamalla tai poistamalla vanhoja viestejäsi; keskustelusta tulee silloin vain sekava. Palautin ensimmäisen viestisi alkuperäiseen muotoonsa.


Sivun alkuun

Vastaus

Aihe on jo aika vanha, joten et voi enää vastata siihen.

Tietoa sivustosta